我在.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();
这不是解决方案。但是当我发现为什么会话仅在调试模式下工作时解决了这个问题。
答案 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序列化不再有麻烦。