JSON.NET и nHibernate Lazy Загрузка коллекций

Кто-нибудь использует JSON.NET с nHibernate? Я замечаю, что я получаю ошибки, когда пытаюсь загрузить class с дочерними коллекциями.

Я столкнулся с той же проблемой, поэтому я попытался использовать код @ 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); } } 

У нас была эта точная проблема, которая была решена с вдохновением от ответа Handcraftsman здесь.

Проблема возникает из-за того, что JSON.NET путается о сериализации прокси-classов NHibernate. Решение: сериализуйте экземпляры прокси-сервера, такие как их базовый class.

Упрощенная версия кода Handcraftsman выглядит следующим образом:

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

IMHO, этот код имеет то преимущество, что по-прежнему полагается на поведение 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.

Я использую NHibernate с Json.NET и замечаю, что я получаю необъяснимые свойства «__interceptors» в моих сериализованных объектах. Поиском Google стало отличное решение Ли Хенсона, которое я адаптировал для работы с Json.NET 3.5 Release 5 следующим образом.

 public class NHibernateContractResolver : DefaultContractResolver { private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers(); protected override List 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(); 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); } } 

Чтобы использовать его, просто введите экземпляр в свойстве ContractResolver вашего JsonSerializer. Проблема круговой зависимости, отмеченная jishi, может быть решена путем установки свойства ReferenceLoopHandling в ReferenceLoopHandling.Ignore. Вот метод расширения, который можно использовать для сериализации объектов с помощью Json.Net

  public static void SerializeToJsonFile(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); } } } 

Получаете ли вы циклическую зависимость-ошибку? Как вы игнорируете объекты из сериализации?

Поскольку ленивая загрузка генерирует прокси-объекты, любые атрибуты, которые у вас есть, будут потеряны. Я столкнулся с той же проблемой с Newtonsoft JSON-serializer, поскольку прокси-объект больше не имел атрибутов [JsonIgnore].

Вероятно, вы захотите загрузить большую часть объекта, чтобы его можно было сериализовать:

  ICriteria ic = _session.CreateCriteria(typeof(Person)); ic.Add(Restrictions.Eq("Id", id)); if (fetchEager) { ic.SetFetchMode("Person", FetchMode.Eager); } 

Хороший способ сделать это – добавить bool к конструктору (bool isFetchEager) вашего метода поставщика данных.

Я бы сказал, что это проблема дизайна, на мой взгляд. Поскольку NH устанавливает соединения с базой данных под всеми и имеет прокси в середине, это не хорошо для прозрачности вашего приложения, чтобы сериализовать их напрямую (и, как вы видите, Json.NET им совсем не нравится).

Вы не должны сериализовать сами сущности, но вы должны преобразовать их в объекты «view» или объекты POCO или DTO (что бы вы ни назвали их), а затем сериализовать их.

Разница в том, что, хотя объект NH может иметь прокси, ленивые атрибуты и т. Д. Просмотреть объекты – это простые объекты с примитивами, которые по умолчанию могут быть сериализованы.

Как управлять FK? Мое личное правило:

Уровень сущности: class Person и связанный с ним class

Уровень просмотра: вид лица с функциями GenderId и GenderName.

Это означает, что вам необходимо расширить свои свойства на примитивы при преобразовании в объекты просмотра. Таким образом, ваши json-объекты проще и проще в обращении.

Когда вам нужно нажать изменения в БД, в моем случае я использую AutoMapper и создаю class ValueResolver, который может преобразовать ваш новый Guid в объект Gender.

ОБНОВЛЕНИЕ. Проверьте http://blog.andrewawhitaker.com/blog/2014/06/19/queryover-series-part-4-transforming/ , чтобы получить представление напрямую (AliasToBean) от NH. Это будет усиление на стороне БД.

  • Сам repository обычно не тестируется?
  • Entity Framework 4 vs NHibernate
  • Запрос на ссылку HasMany
  • Последовательный GUID в Linq-to-Sql?
  • Минимальный и правильный способ сопоставления «один ко многим» с NHibernate
  • Есть ли веские причины не использовать ОРМ?
  • Невозможно применить объект типа NHibernate.Collection.Generic.PersistentGenericBag к списку
  • Идентификация прокси-classов NHibernate
  • NHibernate AliasToBean трансформаторные ассоциации
  • Обратный атрибут в NHibernate
  • AppFabric: не удалось связаться с службой кеша
  • Давайте будем гением компьютера.