流畅的nhibernate:如何使用属性为接口的属性映射实体?

时间:2009-05-11 19:29:27

标签: c# nhibernate fluent-nhibernate interface nhibernate-mapping

我有一个像:

这样的实体
public class Employee
{
    public int ID { get; set; }
    public IAccountManager AccountManager { get; set; }
    ...
}

我还为“DefaultAccountManager”定义了一个映射 - 一个IAccountManager的具体实现。映射上面的“Employee”实体时,如何告诉NHibernate使用“DefaultAccountManager”中定义的映射来持久保存/加载AccountManager属性?

修改 实际上,如果我可以为IAccountManager设置一个映射,那么NHibernate可以只推断哪个实现者加载/持久化会更好。我宁愿不必通过强制所有实现者使用相同的映射来打破多态性。

3 个答案:

答案 0 :(得分:4)

我确实找到了这个答案。几个月前,我对细节有些模糊,但以下是解决方案的主旨:

  • 为具有映射的IAccountManager的每个实现创建一个表。
  • 确保您的数据库设置为使用HiLo id算法。
  • 在映射中使用union-subclasses

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范例,那么请三思而行,实体通常几乎没有行为,接口在这种情况下提供很少 - 如果有的话 - 值。