一个bug调试了半天,才发现跟NHibernate透明代理有关。
用测试代码验证了一下:
ClassA有两个属性S1和S2,S1使用NHibernate持久化,S2不需要持久化。
public
class
ClassA
{
private
int
_id;
private
string
_s1;
private
string
_s2;
public
virtual
int
ID
{
get
{
return
this
._id; }
set
{
this
._id
=
value; }
}
public
virtual
string
S1
{
get
{
return
this
._s1; }
set
{
this
._s1
=
value; }
}
internal
virtual
string
S2
{
get
{
return
this
._s2; }
}
public
virtual
ClassA DoSomething(
string
s1,
string
s2)
{
this
._s1
=
s1;
this
._s2
=
s2;
return
this
;
}
}
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.2"
namespace
="AA.CMS"
assembly
="aa.cms"
>
<
class
name
="ClassA"
table
="TableA"
>
<
id
name
="ID"
>
<
column
name
="ID"
sql-type
="NUMBER(8,0)"
not-null
="true"
/>
<
generator
class
="assigned"
/>
</
id
>
<
property
name
="S1"
>
<
column
name
="S1"
sql-type
="NVARCHAR2"
length
="25"
not-null
="false"
/>
</
property
>
</
class
>
</
hibernate-mapping
>
public
class
ClassB
{
public
string
Get(ClassA a)
{
return
a.S2;
}
}
测试代码:
[Test]
public
void
Test()
{
ISession session
=
TestSetup.GetSession();
ClassA a1
=
session.Load
<
ClassA
>
(
1
);
ClassA a2
=
a1.DoSomething(
"
xxx
"
,
"
yyy
"
);
ClassB b
=
new
ClassB();
DebugUtil.Output(a1.GetType().FullName);
DebugUtil.Output(a1.S1
+
"
---
"
+
b.Get(a1));
DebugUtil.Output(a2.GetType().FullName);
DebugUtil.Output(a2.S1
+
"
---
"
+
b.Get(a2));
session.Close();
}
输出结果:
CProxyTypeAA_CMSClassACMS_NHibernate_ProxyINHibernateProxy1
xxx ---
AA.CMS.ClassA
xxx --- yyy
session.Load()返回的实体对象都是一个透明代理,当访问这个透明代理的public方法
(NHibernate要求这些方法都是virtual类型的,用于从它继承实现透明代理对象)时,构造出实际的实体对象。
问题表现在ClassB.Get()方法里面,它访问的是一个internal类型的属性S2,当传入的是一个透明代理时,internal的属性值S2无法获取到。可能是透明代理在internal类型的方法处理上有问题。
如果想基于NHibernate使用充血模型,得好好注意透明代理的一些副作用了。