如何序列化NHibernate映射对象的所有属性?

我有一些Web方法将我的对象作为序列化XML返回。 它只是序列化对象的NHibernate映射属性……任何人都有一些洞察力? 似乎Web方法实际上是序列化NHibernate代理而不是我的类。 我尝试过使用[XMLInclude]和[XMLElement],但属性仍然没有序列化。 我有一种非常糟糕的hackish方式绕过这个,但我想知道是否有更好的方法!

像这样的东西:

             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属性),那么该属性将不会被序列化。 现在我正在研究使用(数据)传输对象,并可能使用reflection…

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

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

如果你想要所有的属性,你必须从数据库加载它们 – 对于一些急切的加载对于其他人来说已经足够了(其中有太多的连接将开始复制数据)你必须以任何你想要的方式访问该属性触发负载。

编辑:

而且我想补充一点 – 通过网络发送您的域名实体总是一个坏主意。 在我的情况下,我学到了很难的方法 – 我通过WebService公开一些实体 – 现在几乎任何更改(重命名属性,删除属性..etc)到我的域使用WS杀死应用程序 – 加上一大堆属性上有[XmlIgnore](不要忘记循环依赖)。

我们很快就会重写 – 但请确保这不是我再做过的事情。 🙂

编辑2

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

如果是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 customDataTypes) { } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { return null; } public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) { return typeDeclaration; } } 

在主持人中实施:

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

同意sirrocco,我有最糟糕的时间尝试通过WCF序列化NHibernate实体,并最终通过reflection完成了DTO解决方案。

编辑:整个解决方案太大了,无法在此发布,并根据我的需求进行定制,因此我将发布一些相关部分:

 [DataContract] public class DataTransferObject { private Dictionary propertyValues = new Dictionary(); private Dictionary fieldValues = new Dictionary(); private Dictionary relatedEntitiesValues = new Dictionary(); private Dictionary primaryKey = new Dictionary(); private Dictionary> subEntities = new Dictionary>(); ... 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 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 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; }