2009-07-27 108 views
7

我有一些web方法将我的对象作为序列化的XML返回。它只是序列化对象的NHibernate映射的属性......任何人都有一些洞察力?这似乎是网络方法实际上序列化NHibernate代理而不是我的类。我试过使用[XMLInclude]和[XMLElement],但属性仍然没有序列化。我有一个非常可怕的解决方法,但我想知道是否有更好的方法!如何序列化NHibernate映射对象的所有属性?

事情是这样的:

<?xml version="1.0" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="StoryManager" assembly="StoryManager"> 
    <class name="Graphic" table="graphics" lazy="false"> 
    <id name="Id" column="id" type="int" unsaved-value="0" > 
     <generator class="identity"/> 
    </id> 

    <property name="Assigned" /> 
    <property name="Due" /> 
    <property name="Completed" /> 
    <property name="UglyHack" insert="false" update="false" /> 


    <many-to-one name="Parent" class="Story" column="story_id"/> 

    </class> 
</hibernate-mapping> 

public class Graphic 
{ 
    private int m_id; 
    public virtual int Id 
    { 
     get { return m_id; } 
     set { m_id = value; } 
    } 

    private DateTime? m_assigned; 
    public virtual DateTime? Assigned 
    { 
     get { return m_assigned; } 
     set { m_assigned = value; } 
    } 

    private DateTime? m_due; 
    public virtual DateTime? Due 
    { 
     get { return m_due; } 
     set { m_due = value; } 
    } 

    private DateTime? m_completed; 
    public virtual DateTime? Completed 
    { 
     get { return m_completed; } 
     set { m_completed = value; } 
    } 

    public bool UglyHack 
    { 
     get { return m_due < m_completed; } // return something besides a real mapped variable 
     set {} // trick NHibernate into thinking it's doing something 
    } 
} 

这显然是没有办法写代码。如果我没有那里的“假”映射(UglyHack属性),那么该属性将不会被序列化。现在我正在考虑使用(数据)传输对象,并可能会使用反射...

+0

请发表一个小例子。 – 2009-07-27 23:24:35

回答

21

序列化NH映射对象的最佳方法是不序列化:)。

如果你通过电线发送它,你应该真的为它创建一个DTO。如果您不想创建该对象,则可以在不想序列化的属性上设置[XmlIgnore]。

如果你想要所有的属性,你必须从数据库中加载所有的属性 - 对于某些人来说,一个热切的加载对于其他人来说已经足够了(如果有太多的加入会开始复制数据),你必须在任何你想要触发负载的方式。

编辑:

而且我想补充另一件事 - 通过电线发送您的域实体是总是一个坏主意。在我的情况中,我学会了这一难题 - 我通过WebService公开了一些实体 - 现在几乎任何改变(重命名属性,删除属性..etc)到我的域使用WS杀死应用程序 - 加上一大堆属性上有[XmlIgnore](不要忘记循环依赖)。

我们很快就会进行重写 - 但请放心,这不是我要有史以来再做一次。 :)

编辑2

您可以使用AutoMapper的数据从实体到DTO传输。他们在网站上有一些例子。

+0

感谢您的提示! – wprl 2009-07-29 15:56:09

+0

我看到你的观点:)现在我只是想弄清楚如何通过反射来生成它们...... – wprl 2009-07-29 16:45:57

0

同意sirrocco,我试图通过WCF序列化NHibernate实体最糟糕的时候,并最终与通过反射一般完成的DTO解决方案。

编辑:整个解决方案是太大,张贴在这里,并定制适合我的需要ofcourse,所以我会发布一些相关的章节:

[DataContract] 
public class DataTransferObject 
{ 
    private Dictionary<string, object> propertyValues = new Dictionary<string, object>(); 
    private Dictionary<string, object> fieldValues = new Dictionary<string, object>(); 
    private Dictionary<string, object> relatedEntitiesValues = new Dictionary<string, object>(); 
    private Dictionary<string, object> primaryKey = new Dictionary<string, object>(); 
    private Dictionary<string,List<DataTransferObject>> subEntities = new Dictionary<string, List<DataTransferObject>>(); 

... 

    public static DataTransferObject ConvertEntityToDTO(object entity,Type transferType) 
    { 
     DataTransferObject dto = new DataTransferObject(); 
     string[] typePieces = transferType.AssemblyQualifiedName.Split(','); 

     dto.AssemblyName = typePieces[1]; 
     dto.TransferType = typePieces[0]; 

     CollectPrimaryKeyOnDTO(dto, entity); 
     CollectPropertiesOnDTO(dto, entity); 
     CollectFieldsOnDTO(dto, entity); 
     CollectSubEntitiesOnDTO(dto, entity); 
     CollectRelatedEntitiesOnDTO(dto, entity); 

     return dto; 
    } 
.... 

    private static void CollectPropertiesOnDTO(DataTransferObject dto, object entity) 
    { 
     List<PropertyInfo> transferProperties = ReflectionHelper.GetProperties(entity,typeof(PropertyAttribute)); 

     CollectPropertiesBasedOnFields(entity, transferProperties); 

     foreach (PropertyInfo property in transferProperties) 
     { 
      object propertyValue = ReflectionHelper.GetPropertyValue(entity, property.Name); 

      dto.PropertyValues.Add(property.Name, propertyValue); 
     } 
    } 

然后,当你想复活的DTO :

private static DTOConversionResults ConvertDTOToEntity(DataTransferObject transferObject,object parent) 
    { 
     DTOConversionResults conversionResults = new DTOConversionResults(); 

     object baseEntity = null; 
     ObjectHandle entity = Activator.CreateInstance(transferObject.AssemblyName, 
                 transferObject.TransferType); 

     if (entity != null) 
     { 
      baseEntity = entity.Unwrap(); 

      conversionResults.Add(UpdatePrimaryKeyValue(transferObject, baseEntity)); 
      conversionResults.Add(UpdateFieldValues(transferObject, baseEntity)); 
      conversionResults.Add(UpdatePropertyValues(transferObject, baseEntity)); 
      conversionResults.Add(UpdateSubEntitiesValues(transferObject, baseEntity)); 
      conversionResults.Add(UpdateRelatedEntitiesValues(transferObject, baseEntity,parent)); 
.... 

    private static DTOConversionResult UpdatePropertyValues(DataTransferObject transferObject, object entity) 
    {    
     DTOConversionResult conversionResult = new DTOConversionResult(); 

     foreach (KeyValuePair<string, object> values in transferObject.PropertyValues) 
     { 
      try 
      { 
       ReflectionHelper.SetPropertyValue(entity, values.Key, values.Value); 
      } 
      catch (Exception ex) 
      { 
       string failureReason = "Failed to set property " + values.Key + " value " + values.Value; 

       conversionResult.Failed = true; 
       conversionResult.FailureReason = failureReason; 

       Logger.LogError(failureReason); 
       Logger.LogError(ExceptionLogger.BuildExceptionLog(ex)); 
      } 
     } 

     return conversionResult; 
    } 
4

如果一个WCF服务,你可以使用一个IDataContractSurrogate

public class HibernateDataContractSurrogate : IDataContractSurrogate 
{ 
    public HibernateDataContractSurrogate() 
    { 
    } 

    public Type GetDataContractType(Type type) 
    { 
     // Serialize proxies as the base type 
     if (typeof(INHibernateProxy).IsAssignableFrom(type)) 
     { 
      type = type.GetType().BaseType; 
     } 

     // Serialize persistent collections as the collection interface type 
     if (typeof(IPersistentCollection).IsAssignableFrom(type)) 
     { 
      foreach (Type collInterface in type.GetInterfaces()) 
      { 
       if (collInterface.IsGenericType) 
       { 
        type = collInterface; 
        break; 
       } 
       else if (!collInterface.Equals(typeof(IPersistentCollection))) 
       { 
        type = collInterface; 
       } 
      } 
     } 

     return type; 
    } 

    public object GetObjectToSerialize(object obj, Type targetType) 
    { 
     // Serialize proxies as the base type 
     if (obj is INHibernateProxy) 
     { 
      // Getting the implementation of the proxy forces an initialization of the proxied object (if not yet initialized) 
      try 
      { 
       var newobject = ((INHibernateProxy)obj).HibernateLazyInitializer.GetImplementation(); 
       obj = newobject; 
      } 
      catch (Exception) 
      { 
       // Type test = NHibernateProxyHelper.GetClassWithoutInitializingProxy(obj); 
       obj = null; 
      } 
     } 

     // Serialize persistent collections as the collection interface type 
     if (obj is IPersistentCollection) 
     { 
      IPersistentCollection persistentCollection = (IPersistentCollection)obj; 
      persistentCollection.ForceInitialization(); 
      //obj = persistentCollection.Entries(); // This returns the "wrapped" collection 
      obj = persistentCollection.Entries(null); // This returns the "wrapped" collection 
     } 

     return obj; 
    } 



    public object GetDeserializedObject(object obj, Type targetType) 
    { 
     return obj; 
    } 

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) 
    { 
     return null; 
    } 

    public object GetCustomDataToExport(Type clrType, Type dataContractType) 
    { 
     return null; 
    } 

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) 
    { 
    } 

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) 
    { 
     return null; 
    } 

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) 
    { 
     return typeDeclaration; 
    } 
} 

Implemen taion在主机上:

foreach (ServiceEndpoint ep in host.Description.Endpoints) 
     { 
      foreach (OperationDescription op in ep.Contract.Operations) 
      { 
       var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>(); 
       if (dataContractBehavior != null) 
       { 
        dataContractBehavior.DataContractSurrogate = new HibernateDataContractSurrogate(); 
       } 
       else 
       { 
        dataContractBehavior = new DataContractSerializerOperationBehavior(op); 
        dataContractBehavior.DataContractSurrogate = new HibernateDataContractSurrogate(); 
        op.Behaviors.Add(dataContractBehavior); 
       } 
      } 
     } 
相关问题