How do I serialize all properties of an NHibernate-mapped object?

后端 未结 3 1602
逝去的感伤
逝去的感伤 2020-12-03 22:41

I have some web methods that return my objects back as serialized XML. It is only serializing the NHibernate-mapped properties of the object... anyone have some insight? I

相关标签:
3条回答
  • 2020-12-03 23:25

    The best way to serialize the NH mapped object is to not serialize it :).

    If you're sending it across the wire you should really create a DTO for it. If you don't want to create that object you can set [XmlIgnore] on properties you don't want serialized.

    If you want all properties, you have to load them ALL from the database - for some an eager load will be enough for others(where too many joins will start duplicating data) you'll have to access that property in any way you want to trigger the load.

    Edit:

    And I'd like to add another thing - sending your domain entities over the wire is always a bad idea. In my case I learned it the hard way - I expose some entities over a WebService - and now almost any change(rename a property, remove a property ..etc ) to my domain kills the app using the WS - plus a whole bunch of properties have [XmlIgnore] on them ( don't forget about circular dependencies).

    We'll do a rewrite soon enough - but rest assure that's not something I'll ever do again. :)

    Edit 2

    You could use AutoMapper for transferring the data from your entity to the DTO. They have some examples on the site.

    0 讨论(0)
  • 2020-12-03 23:34

    if its a WCF service, you could use a 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;
        }
    }
    

    Implementaion in the host:

    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);
                    }
                }
            }
    
    0 讨论(0)
  • 2020-12-03 23:35

    Agree with sirrocco, I've had the most awful time trying to serialize NHibernate entities through WCF, and eventually went with a DTO solution done generically through reflection.

    Edit: The entire solution is too big to post here, and is customized for my needs ofcourse, so I'll post a few relevant sections:

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

    then, when you want to resurrect the 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;
        }
    
    0 讨论(0)
提交回复
热议问题