Fluent NHibernate引用打印“__interceptor”对象而不是域对象

时间:2016-11-15 13:05:20

标签: c# nhibernate fluent-nhibernate

我在.Net Web Api项目中有两个名为User和Role的简单类。

用户类是:

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类中表示它并不感兴趣。

当我从数据库中获取用户时,属性“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命令的控制台,没有调用检索角色记录的命令。

那么,我在这里失踪了什么?为什么没有根据域的定义正确获取类Role?

更新

感谢RadimKöhler的回答,我意识到问题不在于Fluent NHibernate,而在于“lazyloading serialization proxy hell”。

根据他的提示,我发现了两个新错误:

第一个:

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

这不是解决方案。但是当我发现为什么会话仅在调试模式下工作时解决了这个问题。

2 个答案:

答案 0 :(得分: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 陷阱获取的方式

答案 1 :(得分: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序列化不再有麻烦。