2016-11-15 12 views
1

У меня есть два простых класса с именем «Пользователь и роль» в проекте .Net Web Api.Fluent NHibernate Ссылки печать объекта «__interceptor» вместо объекта домена

Класс Пользователь:

public class User 
{ 
    public virtual int Id { get; set; } 
    public virtual int RoleId { get; set; } 
    public virtual string Name { get; set; } 
    public virtual Role Role{ get; set; } 

    public User() { } 
} 

А класс Роль является:

public class Role 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 

    public Role() { } 
} 

Отображения с использованием свободно являются:

Пользователь:

public UserMap() 
{ 
    Table("plc_users"); 
    Id(x => x.Id).Column("usr_id"); 
    Map(x => x.RoleId).Column("rol_id"); 
    Map(x => x.Name).Column("usr_name"); 
    References(x => x.Role).Column("rol_id"); 
} 

Роль:

public RoleMap() 
{ 
    Table("plc_roles"); 
    Id(x => x.Id).Column("rol_id"); 
    Map(x => x.Name).Column("rol_name"); 
} 

Это односторонние отношения между пользователем и ролью. Пользователь имеет роль. Хотя роль может присутствовать у многих пользователей, в этом случае не представляется интересным представлять это в классе Role.

Когда я получаю пользователя из базы данных, свойство «Роль» получает неправильное значение. Оно должно быть:

{ 
    "Id" : "2", 
    "RoleId" : "1", 
    "Name" : "Any", 
    "Role": { 
     "Id": "1", 
     "Name" : "Any" 
    } 
} 

Но это становится:

{ 
    "Id" : "2", 
    "RoleId" : "1", 
    "Name" : "Any", 
    "Role": { 
     "__interceptor": { 
       "persistentClass": "NameSpaceForClass, , Version=1.0.0.0 [...] 
       "getIdentifierMethod": { 
     [...] 
     }, 
} 

Наблюдая консоль для команд SQL, выполняемых NHibernate, не была названа команда для извлечения записи роли.

Итак, что мне здесь не хватает? Почему роль класса не правильно выбрана в соответствии с определением домена?

UPDATE:

Благодаря ответу Радим Келер, я понял, что проблема была не с Fluent NHibernate, но с «lazyloading сериализации прокси-ад».

После его советы, я обнаружил две новые ошибки:

Первое:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8' 

И внутренний:

Could not initialize proxy - no Session. 

Я использую сессию в рамках действия что означает, что сеанс начинается в начале действия и закрывается в конце. Исходя из этого, я начал несколько способов понять, почему сессия закрывалась до сериализации Json. Множество конфигураций позже, я заметил, что в режиме отладки все работает нормально. И это было странно.

Во всяком случае, я не получаю нигде, так что я решил выключить режим LazyLoad, как это:

References(x => x.Role).Column("rol_id").ReadOnly().Not.LazyLoad(); 

Это не решение. Но решает проблему, пока я застрял в выяснении, почему сеанс работает только в режиме отладки.

ответ

0

Проверить эти

и вслед за ними, ввести свой собственный контракт распознаватель

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

Хитрость заключается в том ... мы используем BaseType, что можно получить от PROXY trap

+0

спасибо! Я сделал еще несколько отладок, и я понял, что проблема не в Fluent NHibernate вообще. Но, как вы сказали, с "lazyloading serialization proxy hell". Это привело меня к другим проблемам. Они описаны в «Обновлении» этого вопроса. –

0

Ну, после некоторого рефакторинга я придумал решение.

Давайте напомним.

Я думал, что проблема связана с картами NHibernate, но я был неправ, они великолепны, работают отлично. Реальная проблема заключалась в сериализации JSON прокси-объекта в коллекции, предоставляемой NHibernate Mapings.

Одним из решений было создание персонализированного адаптера для обучения NHibernate для обработки дочерних объектов, таких как их базовый класс. Это действительно работает, но привело меня к другой проблеме, на этот раз к проблеме, не связанной с сеансом.

После некоторой борьбы и некоторых мыслей, я решил изменить архитектуру своего решения Web Api, создав новый слой для передачи данных. Поэтому вместо отправки сущности в браузер я просто отправляю эквивалентный DTO (объект передачи данных).

Чтобы сделать сопоставление между Entity и его эквивалентом DTO, я использую AutoMapper. При таком подходе, когда происходит сериализация JSON, объект будет со всеми установленными свойствами и больше не будет зависеть от объектов-прокси-серверов NHibernate.

С точки зрения кода, что я сделал:

Config AutoMapper:

Mapper.Initialize(cfg => cfg.CreateMap<User, UserDto>()); 
Mapper.Initialize(cfg => cfg.CreateMap<Role, RoleDto>()); 

Создание DTOs:

public class UserDto 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public RoleDto Role{ get; set; } 
} 

public class RoleDto 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

Выполните синтаксический разбор:

IList<RoleDto> dtoList = Mapper.Map<RoleDto>(listOfUsers); 

Вот и все. Больше никаких проблем с сериализацией JSON.