我有一个像:
这样的实体public class Employee
{
public int ID { get; set; }
public IAccountManager AccountManager { get; set; }
...
}
我还为“DefaultAccountManager”定义了一个映射 - 一个IAccountManager的具体实现。映射上面的“Employee”实体时,如何告诉NHibernate使用“DefaultAccountManager”中定义的映射来持久保存/加载AccountManager属性?
修改 实际上,如果我可以为IAccountManager设置一个映射,那么NHibernate可以只推断哪个实现者加载/持久化会更好。我宁愿不必通过强制所有实现者使用相同的映射来打破多态性。
答案 0 :(得分:4)
我确实找到了这个答案。几个月前,我对细节有些模糊,但以下是解决方案的主旨:
Union-subclasses看起来像这样:
<class name="IAccountManager" abstract="true">
<id name="ID" column="ID" type="Int32">
<generator class="hilo"/>
</id>
<union-subclass name="DefaultAccountManager" table="DefaultAccountManager"
proxy="IAccountManager">
<property name="FirstName" type="String"/>
<property name="LastName" type="String"/>
</union-subclass>
... more implementations
</class>
注意union-subclass上的属性“name”。对于IAccountManager的每个实现,这应该是唯一的(并匹配)。
此外,ID(而不是每个表的唯一ID)对所有IAccountManagers都是唯一的(通过利用hilo)。
当NHibernate看到一个IAccountManager实体时,它将使用实例的具体类型和union-subclass定义来找出正确的表。
希望这有帮助!
答案 1 :(得分:1)
以为我会分享一种方法,我设法使用Fluent NHibernate而不是hbm文件来实现这一点。
这种方法有点hacky,但是一旦Fluent NH获得对Union-Subclass的适当支持,黑客就会被隔离并且很容易被删除。
要使用您的示例,我的方案的上下文是这样的 - Employee类在一个项目中,AccountManager属性被指定为接口,因为具体的AccountManager在不同的项目中,我们不想创建一个依赖于。
首先,我创建了一个'Helper'类,它可以执行大部分Employee映射,看起来像这样。
public abstract class EmployeeMapperBase
{
protected abstract Type GetAccountManagerType();
public void DoMapping(ClassMap<Employee> classMap)
{
classMap.Id(x => x.Id);
classMap.Maps(..... etc....
classMap.References(x => x.AccountManager)
.Class(GetAccountManagerType());
}
}
接下来,在具有具体AccountManager类的项目中,我完成了映射:
public class EmployeeClassMap : ClassMap<Employee>
{
public EmployeeClassMap
{
new ConcreteEmployeeMapper().DoMapping(this);
}
private class ConcreteEmployeeMapper : EmployeeMapperBase
{
public override Type GetAccountManagerType()
{
return typeof(DefaultAccountManager);
}
}
}
答案 2 :(得分:0)
如果您需要多态性,因为IAccountManager实现的功能可能具有不同的功能,您可以查看discriminators并使用基类而不是接口。
如果您只是使用接口,因为它们是OOP范例,那么请三思而行,实体通常几乎没有行为,接口在这种情况下提供很少 - 如果有的话 - 值。