2016-11-15 65 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序列化没有更多的麻烦。