7

私はオブジェクトをシリアル化されたXMLとして返すいくつかのWebメソッドを持っています。それは、オブジェクトのNHibernateにマップされたプロパティをシリアル化するだけです...誰もいくつかの洞察力を持っていますか? Webメソッドは実際にはクラスの代わりにNHibernateのプロキシをシリアライズしているようです。私は[XMLInclude]と[XMLElement]を使ってみましたが、プロパティはまだシリアル化されていません。私はこれを回避するために本当に恐ろしいhackish方法がありますが、より良い方法があるかどうか疑問に思った!このような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

小さな例を投稿してください。 –

答えて

21

NHマッピングされたオブジェクトをシリアル化する最善の方法はそれをシリアル化しないでください:)。

ワイヤを介して送信する場合は、本当にDTOを作成する必要があります。そのオブジェクトを作成したくない場合は、シリアル化したくないプロパティで[XmlIgnore]を設定することができます。

すべてのプロパティが必要な場合は、データベースからALLをロードする必要があります。熱心な負荷では十分です(結合が多すぎるとデータの複製が開始される)ため、そのプロパティにアクセスする必要があります負荷をトリガーする方法。

編集:

そして、私は別のものを追加したい - ワイヤーの上にドメインエンティティを送信することは、常に悪い考えです。私の場合、難しい方法を学んだ - 私はWebService上でいくつかのエンティティを公開する - そして今、私のドメインへのほとんどすべての変更(プロパティの名前を変更し、プロパティなど..)は、WSを使用してアプリを殺す+プロパティには[XmlIgnore]があります(循環依存性を忘れないでください)。

すぐに書き直しを行いますが、それは私がに今までしていないことを確認してください。 :)

編集2

あなたはDTOにあなたのエンティティからデータを転送するためAutoMapperを使用することができます。彼らはサイト上でいくつかの例を持っています。

+0

チップをありがとう! – wprl

+0

私はあなたのポイントを参照してください:)今私は反射を通してそれらを生成する方法を理解しようとしています... – wprl

+1

+1優れた答え! –

0

私はsirroccoと合意していますが、私はWCFを通してNHibernateエンティティをシリアル化しようとする最も恐ろしい時を過ごしました。

編集:全体のソリューションはここに投稿するには大きすぎる、とofcourseの私のニーズに合わせてカスタマイズされているので、私はいくつかの関連セクション投稿します:あなたはDTOを復活したい場合は、

[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); 
     } 
    } 

を: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を使用することができ、その場合

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; 
    } 
+0

例を投稿してください。 – wprl

+0

非常に興味深い – wprl

+1

AutoMapperはこの作業を行いませんか? – Lijo

4

ホストで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); 
       } 
      } 
     } 
関連する問題