JSON.NET和nHibernate Lazy加载集合

use*_*326 32 nhibernate json.net

是否有人使用JSON.NET和nHibernate?我注意到当我尝试加载具有子集合的类时,我遇到了错误.

Ali*_*uri 42

我遇到了同样的问题,所以我尝试使用@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);
      }
  }
Run Code Online (Sandbox Code Playgroud)

  • +1 - 这似乎是NH 3.3和JSON.NET 4.5.7现在唯一的工作版本. (3认同)

Lie*_*man 25

我们有这个确切的问题,这是在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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

恕我直言,这段代码的优势仍然是依赖于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();
Run Code Online (Sandbox Code Playgroud)

注意:此代码是为NHibernate 2.1编写并使用的.正如一些评论者指出的那样,它不能与更新版本的NHibernate一起开箱即用,你将不得不做一些调整.如果我必须使用更新版本的NHibernate,我会尝试更新代码.


Han*_*man 18

我使用NHibernate和Json.NET,并注意到我在序列化对象中得到了莫名其妙的"__interceptors"属性.谷歌搜索出现了Lee Henson的这个出色的解决方案,我适应了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);
  }
}
Run Code Online (Sandbox Code Playgroud)

要使用它,只需在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);
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

  • 感谢您使用此代码,它非常棒!并使我免于使用StatelessSession. (2认同)

jis*_*shi 3

您是否遇到循环依赖错误?如何忽略序列化中的对象?

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

  • 对比你早 1.5 年写的答案投反对票,有点弱智吗? (2认同)