我有一个简单的域模型,实体租户和客户(前者是聚合)。我还有一个CustomerCode值对象。这些类看起来如下。
class Tenant() {
private Guid _id;
private Customer _customer;
public Tenant(CustomerCode cc) {
_customer = new Customer(this, cc);
}
public virtual Customer {
get => _customer;
protected set => _customer = value;
}
//etc
}
class Customer {
private Guid _id;
private Tenant _parent;
private CustomerCode _code;
internal Customer(Tenant parent, CustomerCode code) {
_parent = parent;
_code = code;
}
public virtual Tenant Parent {
get => _parent;
protected set => _parent = value;
}
public virtual CustomerCode Code {
get => _code;
protected set => _code = value;
}
//etc
}
class CustomerCode {
private string _value;
public CustomerCode(string value) {
// some validations
_value = value;
}
public virtual string Value {
get => _value;
protected set => _value = value;
}
// etc
}
租户和客户有一对一的关系,如HBM文件中所定义。
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="..." assembly="...">
<class name="Tenant" table="Tenants">
<id name="Id" column="Id" type="Guid">
<generator class="guid" />
</id>
<!-- etc -->
<many-to-one name="Customer" unique="true" column="CustomerId"
class="Customer" not-null="true" cascade="save-update "/>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="..." assembly="...">
<class name="Customer" table="Customers">
<id name="Id" column="Id" type="Guid">
<generator class="guid" />
</id>
<component name="Code">
<property name="Value" column="Code" />
</component>
<!-- etc -->
<one-to-one name="Tenant" class="Tenant" property-ref="Customer" />
</class>
</hibernate-mapping>
最后,我有以下测试用例。这里,CreateSession返回一个ISession。
[TestMethod]
public void CreateTenantTest()
{
var session = CreateSession();
object tenantId;
using (var tran = session.BeginTransaction()) {
var customerCode = new CustomerCode("BW1801");
var item = new Tenant(customerCode);
tenantId = session.Save(item);
tran.Commit();
}
session.Clear();
var ts = session.Get<Tenant>(tenantId);
Assert.AreEqual(tenantId, ts.Id);
//some other asserts
Assert.IsNotNull(ts.Customer);
Assert.AreEqual("BW1801", ts.Customer.Code.Value); // <--this won't work
}
测试用例中的最后一个断言导致Visual Studio 2017的测试系统因为stackoverflow异常而停止。完整的信息是:
The active test run was aborted. Reason: Process is terminated
due to StackOverflowException
如果我评论最后一个断言,则测试功能正常。调试测试用例没有结果,因为VS只是冻结而且我必须杀死VStest进程。
鉴于这对Customer不起作用,我开始怀疑延迟加载有问题。所以我更改了两个HBM.XML文件的声明以禁用延迟加载:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="..." assembly="...">
<class name="Tenant" table="Tenants" lazy="true">
<!-- etc -->
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="..." assembly="...">
<class name="Customer" table="Customers" lazy="true">
<!-- etc -->
</class>
</hibernate-mapping>
它工作正常,StackOverflowException问题消失了,测试用例通过并正确设置了值。现在,我可以继续工作,但我不觉得轻松禁用延迟加载,因为它是一个可以在面临瓶颈或资源消耗时提供帮助的功能。此外,也许我搞砸了一些东西,而我只是把虫子扫到地毯下面。
任何人都可以解释为什么会出现这种情况吗?我是在忽略某些东西,或者在某个地方错过设置?