2016-11-15 110 views
1

我有兩個命名爲用戶和角色在.NET的Web API項目簡單的類。功能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": { 
     [...] 
     }, 
} 

觀察由NHibernate的執行的SQL命令的控制檯,用於檢索角色記錄的命令不被調用。

所以,我在想什麼嗎?爲什麼根據域的定義,類角色沒有被正確取出?

UPDATE:

得益於拉迪姆·克勒的回答,我意識到這個問題是不是與功能NHibernate,但與「惰性加載系列化代理地獄」。

在他的提示,我發現了兩個新的錯誤:

第一:

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陷阱

+0

非常感謝!我做了一些更多的調試,並且我意識到這個問題與Fluent NHibernate完全不同。但是,正如你所說的,「懶惰加載序列化代理地獄」。這導致我對其他問題。它們在這個問題的「更新」中描述。 –

0

好吧,經過一些重構,我想出了一個解決方案。

讓我們回顧一下。

我認爲問題出在NHibernate Mapings上,但我錯了,他們很棒,工作得很好。真正的問題在於由NHibernate Mapings提供的集合中的代理對象的JSON序列化。

其中一個解決方案是創建一個自定義合約解析器,教NHibernate處理子對象,如他們的基類。這確實有效,但卻導致我出現另一個問題,這次是「沒有會話限制」的問題。

經過一番鬥爭和一些思考之後,我選擇通過創建一個新層來作爲數據傳輸來改變我的Web Api解決方案的體系結構。因此,我不是發送實體到瀏覽器,而是發送等效的DTO(數據傳輸對象)。

要做實體和它的DTO等價物之間的映射,我使用AutoMapper。通過這種方法,當發生JSON序列化時,對象將被設置爲所有屬性,不再依賴於NHibernate代理對象。

在代碼方面,我所做的就是:

配置AutoMapper:

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

創建的DTO:

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序列化沒有更多的麻煩。