2009-07-27 90 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); 
       } 
      } 
     } 
相關問題