我有一些Web方法可以将我的对象作为序列化XML返回。它只是序列化对象的NHibernate映射属性......任何人都有一些洞察力?似乎Web方法实际上是序列化NHibernate代理而不是我的类。我尝试过使用[XMLInclude]和[XMLElement],但属性仍然没有序列化。我有一种非常糟糕的hackish方式绕过这个,但我想知道是否有更好的方法!
这样的事情:
<?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]。
如果你想要所有的属性,你必须从数据库加载它们 - 对于一些急切的加载对于其他人来说已经足够了(其中有太多的连接将开始复制数据)你将不得不以任何方式访问该属性你想要触发负载。
修改强>
我想添加另一件事 - 通过网络发送您的域名实体是总是一个坏主意。在我的情况下,我学习了很难的方法 - 我通过WebService公开一些实体 - 现在几乎任何更改(重命名属性,删除属性..etc)到我的域使用WS杀死应用程序 - 加上一大堆属性上有[XmlIgnore](不要忘记循环依赖)。
我们很快就会重写 - 但请确保我不会再次再做一次。 :)
修改2
您可以使用AutoMapper将数据从实体传输到DTO。他们在网站上有一些例子。
答案 1 :(得分: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;
}
}
在主持人中实施:
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);
}
}
}
答案 2 :(得分:0)
同意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;
}