2008-11-13 82 views
30

是否有人使用JSON.NET与nHibernate?我注意到当我尝试使用子集合加载类时出现错误。JSON.NET和nHibernate延迟加载集合

+2

可否请您发布有关您所看到的错误的详细信息? – 2008-11-13 20:30:10

+0

我正在'方法或操作未执行'。并且Liedman的修复为我工作。 – 2011-10-14 14:51:19

回答

3

你是否得到一个循环依赖性错误?你如何忽略序列化的对象?

由于延迟加载会生成代理对象,因此您的类成员拥有的任何属性都将丢失。我遇到了与Newtonsoft JSON序列化程序相同的问题,因为代理对象不再具有[JsonIgnore]属性。

+0

看到我的和Handcraftsman的回复,他们包含一个解决方案,正是这个问题。 – Liedman 2010-09-20 08:55:53

+2

一种迟到的投票回答是在你的1,5年之前写的吗? – jishi 2010-09-21 13:03:21

+0

是的,这正是我遇到的问题。当我得到错误时,我没有忽略任何来自序列化的对象。我想我需要回去仔细阅读文档! – user32326 2008-11-16 13:55:19

3

你可能会想急于负荷大部分对象,以便它可以被序列化:

 ICriteria ic = _session.CreateCriteria(typeof(Person)); 

     ic.Add(Restrictions.Eq("Id", id)); 

     if (fetchEager) 
     { 
      ic.SetFetchMode("Person", FetchMode.Eager); 
     } 

一个很好的方式做,这是一个布尔添加到构造(布尔isFetchEager)数据的提供者方法。

18

我使用NHibernate和Json.NET,并注意到我在序列化对象中出现莫名其妙的“__interceptors”属性。谷歌搜索由Lee Henson翻译成了this excellent solution,我修改了如下的Json.NET 3.5 Release 5。

public class NHibernateContractResolver : DefaultContractResolver 
{ 
    private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers(); 

    protected override List<MemberInfo> GetSerializableMembers(Type objectType) 
    { 
    var members = base.GetSerializableMembers(objectType); 

    members.RemoveAll(memberInfo => 
         (IsMemberPartOfNHibernateProxyInterface(memberInfo)) || 
         (IsMemberDynamicProxyMixin(memberInfo)) || 
         (IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) || 
         (IsMemberInheritedFromProxySuperclass(memberInfo, objectType))); 

    var actualMemberInfos = new List<MemberInfo>(); 

    foreach (var memberInfo in members) 
    { 
     var infos = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name); 
     actualMemberInfos.Add(infos.Length == 0 ? memberInfo : infos[0]); 
    } 

    return actualMemberInfos; 
    } 

    private static bool IsMemberDynamicProxyMixin(MemberInfo memberInfo) 
    { 
    return memberInfo.Name == "__interceptors"; 
    } 

    private static bool IsMemberInheritedFromProxySuperclass(MemberInfo memberInfo, Type objectType) 
    { 
    return memberInfo.DeclaringType.Assembly == typeof(INHibernateProxy).Assembly; 
    } 

    private static bool IsMemberMarkedWithIgnoreAttribute(MemberInfo memberInfo, Type objectType) 
    { 
    var infos = typeof(INHibernateProxy).IsAssignableFrom(objectType) 
        ? objectType.BaseType.GetMember(memberInfo.Name) 
        : objectType.GetMember(memberInfo.Name); 

    return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0; 
    } 

    private static bool IsMemberPartOfNHibernateProxyInterface(MemberInfo memberInfo) 
    { 
    return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name); 
    } 
} 

要使用它,只是把一个实例在JsonSerializer的ContractResolver财产。通过将ReferenceLoopHandling属性设置为ReferenceLoopHandling.Ignore可以解决由jishi记录的循环依赖关系问题。下面是可以用于使用Json.Net

public static void SerializeToJsonFile<T>(this T itemToSerialize, string filePath) 
    { 
    using (StreamWriter streamWriter = new StreamWriter(filePath)) 
    { 
     using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter)) 
     { 
     jsonWriter.Formatting = Formatting.Indented; 
     JsonSerializer serializer = new JsonSerializer 
      { 
      NullValueHandling = NullValueHandling.Ignore, 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
      ContractResolver = new NHibernateContractResolver(), 
      }; 
     serializer.Serialize(jsonWriter, itemToSerialize); 
     } 
    } 
    } 
23

我们有这个确切的问题,这是解决了这里的灵感来自Handcraftsman的响应对象序列扩展方法。

问题出在JSON.NET对如何序列化NHibernate的代理类感到困惑。解决方案:序列化代理实例,如其基类。

的Handcraftsman的代码的简化版本是这样的:

public class NHibernateContractResolver : DefaultContractResolver { 
    protected override List<MemberInfo> GetSerializableMembers(Type objectType) { 
     if (typeof(INHibernateProxy).IsAssignableFrom(objectType)) { 
      return base.GetSerializableMembers(objectType.BaseType); 
     } else { 
      return base.GetSerializableMembers(objectType); 
     } 
    } 
} 

恕我直言,这个代码有仍然依靠关于自定义属性,等等JSON.NET的默认行为的优势(和代码是很多短!)。

它这样使用

 var serializer = new JsonSerializer{ 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
      ContractResolver = new NHibernateContractResolver() 
     }; 
     StringWriter stringWriter = new StringWriter(); 
     JsonWriter jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);     
     serializer.Serialize(jsonWriter, objectToSerialize); 
     string serializedObject = stringWriter.ToString(); 

注:此代码编写,并与NHibernate 2.1使用。正如一些评论者指出的那样,NHibernate的后期版本并不适用,你将不得不做一些调整。我会尝试更新代码,如果我必须使用NHibernate的更高版本来完成。

41

我面临同样的问题,所以我试图使用@ Liedman的代码,但GetSerializableMembers()从未被称为代理引用。 我发现了另一个方法重写:

public class NHibernateContractResolver : DefaultContractResolver 
    { 
     protected override JsonContract CreateContract(Type objectType) 
     { 
      if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType)) 
       return base.CreateContract(objectType.BaseType); 
      else 
       return base.CreateContract(objectType); 
     } 
    } 
1

我会说这在我看来是一个设计问题。由于NH与所有数据库连接,中间有代理,所以它不利于应用程序直接序列化它们的透明性(正如你可以看到的,Json.NET根本不喜欢它们)。

你不应该序列化实体本身,但你应该将它们转换成“视图”对象或POCO或DTO对象(无论你想调用它们),然后将它们序列化。

不同之处在于,虽然NH实体可能具有代理,惰性属性等。查看对象是只有基本类型的简单对象,默认情况下它们是可序列化的。

如何管理FK? 我个人的原则是:

实体一级:Person类和关联

查看水平性别类:与GenderId和GenderName性个人检视。

这意味着在转换为视图对象时需要将属性扩展为基元。这样,你的json对象也更简单,更容易处理。

当您需要将更改推送到数据库时,我使用AutoMapper并执行一个ValueResolver类,它可以将您的新Guid转换为Gender对象。

更新:检查http://blog.andrewawhitaker.com/blog/2014/06/19/queryover-series-part-4-transforming/获取NH中直接获取视图(AliasToBean)的方法。这将会对数据库方面起到推动作用。