31 votos

JSON.NET y nHibernate Carga Diferida de Colecciones

Es una persona utiliza JSON.NET con nHibernate? Me doy cuenta de que estoy recibiendo errores cuando intento cargar una clase con los niños de las colecciones.

Gracias

Graham

42voto

sos00 Puntos 725

Me estaba enfrentando el mismo problema, así que he intentado usar @Liedman del código, pero el GetSerializableMembers() nunca fue llamado por el proxy de referencia. He encontrado otro método para anular:

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

24voto

Liedman Puntos 3144

Hemos tenido este problema exacto, que fue resuelto con la inspiración de Handcraftsman la respuesta aquí.

El problema surge a partir de JSON.NET estar confundidos acerca de cómo serializar NHibernate clases de proxy. Solución: serializar el proxy casos como el de su clase base.

Una versión simplificada de Handcraftsman del código va como esto:

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

En mi humilde opinión, este código tiene la ventaja de que siguen confiando en la JSON.NET's comportamiento por defecto con respecto a los atributos personalizados, etc. (y el código es mucho más corto!).

Es utilizado como esta

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

Nota: Este código fue escrito para ser usado con NHibernate 2.1. Como algunos comentaristas han señalado, no funciona fuera de la caja con las versiones posteriores de NHibernate, usted tendrá que hacer algunos ajustes. Voy a tratar de actualizar el código si alguna vez tengo que hacerlo con las versiones posteriores de NHibernate.

18voto

Handcraftsman Puntos 3166

Puedo usar NHibernate con Json.NET y noté que me estaba poniendo inexplicable "__interceptores" propiedades de mis objetos serializados. Una búsqueda de google activado este excelente solución por Lee Henson que he adaptado para trabajar con Json.NET 3.5 Release 5 como sigue.

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

Para usarlo sólo poner un ejemplo, en el ContractResolver propiedad de su JsonSerializer. La circular problema de dependencia señaló jishi puede ser resuelto por la configuración de la ReferenceLoopHandling propiedad ReferenceLoopHandling.Ignorar . He aquí un método de extensión que se puede utilizar para serializar objetos de uso 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);
      }
    }
  }

3voto

jishi Puntos 10442

¿Usted está consiguiendo una circular de dependencia-error? ¿Cómo ignorar los objetos de la serialización?

Dado que la carga diferida genera un proxy-objetos, los atributos de su clase-los miembros tienen perdida. Me encontré con el mismo problema con Newtonsoft JSON-serializador, ya que el proxy-objeto de no tener la [JsonIgnore] atributos más.

3voto

David P Puntos 2430

Usted probablemente va a querer con ganas de carga de la mayoría de los objetos, de modo que puede ser la serie:

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

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

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

Una buena manera de hacer esto es agregar un booleano para el constructor (bool isFetchEager) de su proveedor de datos método.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: