【问题标题】:How do I serialize all properties of an NHibernate-mapped object?如何序列化 NHibernate 映射对象的所有属性?
【发布时间】:2010-11-14 12:17:50
【问题描述】:

我有一些 Web 方法可以将我的对象作为序列化 XML 返回。它只是序列化对象的 NHibernate 映射属性......有人有一些见识吗?似乎网络方法实际上是在序列化 NHibernate 代理而不是我的类。我试过使用 [XMLInclude] 和 [XMLElement],但属性仍然没有序列化。我有一个非常可怕的黑客方法来解决这个问题,但我想知道是否有更好的方法!

类似这样的:

<?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 属性),则该属性将不会被序列化。现在我正在研究使用(数据)传输对象,并且可能会使用反射来做一些事情......

【问题讨论】:

    标签: c# web-services nhibernate xml-serialization proxy-classes


    【解决方案1】:

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

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

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

    编辑:

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

    我们会尽快进行重写 - 但请放心,我不会永远再次这样做。 :)

    编辑 2

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

    【讨论】:

    • 我明白你的意思了 :) 现在我只是想弄清楚如何通过反射来生成它们......
    【解决方案2】:

    同意 Sirrocco,我经历了最糟糕的时间尝试通过 WCF 序列化 NHibernate 实体,最终选择了一个通过反射完成的 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);
            }
        }
    

    那么,当你想复活 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;
        }
    

    【讨论】:

    • AutoMapper 不会做这个任务吗?
    【解决方案3】:

    如果它是 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;
        }
    }
    

    在宿主中的实现:

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

    【讨论】:

      猜你喜欢
      • 2022-08-18
      • 2011-06-18
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 2013-06-26
      • 2022-01-01
      相关资源
      最近更新 更多