如何使用与父ID不同的列映射到已连接的子类?

时间:2012-10-03 22:44:54

标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我正在使用brownfield数据库,并且我正在尝试配置一个子类映射,该映射使用除指定id之外的列连接到其子类。 login表有一个主键列login_sk,我想将其用作id。它通过login_cust_id列连接到两个表(为了使相邻表中相应列的命名方式更加有趣)。如果我将login_cust_id设置为UserMap的id,则会按预期连接到其子类。我希望显而易见的原因是我不想使用login_cust_id作为我的User对象的id。

public class UserMap : ClassMap<IUser>
{
    public UserMap()
    {
        Table("login");
        Id(x => x.Id).Column("login_sk"); // want to setup map like this

        // if used instead this works for subclass joining / mapping
        // Id(x => x.Id).Column("login_cust_id");
        // would prefer to only reference login_cust_id for subclass mapping
    }
}

public class CustomerUserMap : SubclassMap<CustomerUser>
{
    public CustomerUserMap()
    {
        Table("customer");
        Map(c => c.DisplayName, "cust_mail_name");
        Map(c => c.RecordChangeName, "cust_lookup_name");
        KeyColumn("cust_id");
    }
}

public class EntityUserMap : SubclassMap<EntityUser>
{
    public EntityUserMap()
    {
        Table("entity");
        Map(c => c.DisplayName, "entity_name");
        KeyColumn("entity_id");
    }
}

我想要做的是在加入子类时只使用login_cust_id列。是否有一个流畅的映射设置,允许我指定这个?如果没有流畅的映射,那么常规的NHibernate XML映射会起作用吗?我甚至不想映射列,只在可能的情况下使用它来加入。如果它有帮助,则有一个潜在的鉴别器列login_holder_type,它指示要加入的表。

我确实设置了IClassConvention,但在通过IClassInstance后,我无法确定任何有助于我的设置。

public class UserIdConvention : IClassConvention, IClassConventionAcceptance
{

    public void Apply(IClassInstance instance)
    {
        // do something awesome with instance.Subclasses to
        // specify the use of login_cust_id for subclass joining...
    }

    public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
    {
        criteria.Expect(x => typeof(User).Equals(x.EntityType));
    }
}

传递的实例缺少填充的Subclasses集合导致我寻找IParentInspector似乎更具体的检查器。遗憾的是,Fluent NHibernate似乎没有IParentInstanceIParentConventionIParentConventionAcceptance的相应实现,就像IJoinedSubclassInspector一样。虽然在我做之前我可能会实现自己的,但我想确保我没有咆哮错误的树。

这种子类id调整是否可行?我在地图或Fluent NHibernate Conventions namespace中遗漏了一些明显的东西吗?如何映射到具有与父ID

不同的列/属性的已连接子类

1 个答案:

答案 0 :(得分:3)

我能够想到三个可能解决您问题的方法,请参阅下面的调查结果。

解决方案1:使用Join

进行基于判别器的映射

我最初的想法是使用基于鉴别器的映射来建模继承,每个子类包含一个带属性ref的连接,即

<class name="IUser" abstract="true" table="login">
    <id name="Id" column="login_sk">
        <generator class="identity"/>
    </id>
    <discriminator column="login_holder_type" not-null="true" type="System.String"/>

    <subclass name="CustomerUser" discriminator-value="Customer">
        <join table="customer" >
          <key column="cust_id" property-ref="login_cust_id" />
          <property name="DisplayName" column="cust_mail_name"/>
          <property name="RecordChangeName" column="cust_lookup_name" />
        </join>
    </subclass>

    <subclass name="EntityUser" discriminator-value="Entity">
      <join table="entity" >        
        <key column="entity_id" property-ref="login_cust_id" />
        <property name="CompanyName"/>
      </join>
    </subclass>
</class>

不幸的是,此时Hibernate支持此功能,但NHibernate不支持。有关优秀门票,请参阅herehere。一些工作已经用于添加此功能,可以在github上的this fork上看到。

解决方案2:基于判别器的映射与多对一

另一种选择是仍然使用基于鉴别器的映射,但在每个子类中使用many-to-one映射,这将允许您使用property-ref连接外键。这样做的缺点是需要为客户和实体表中的所有属性提供单独的类,但这是一个可行的解决方案。

<class name="IUser" abstract="true" table="login">
    <id name="Id" column="login_sk">
        <generator class="identity"/>
    </id>
    <discriminator column="login_holder_type" not-null="true" type="System.String"/>

    <subclass name="CustomerUser" discriminator-value="Customer">
        <many-to-one name="CustomerProps" property-ref="login_cust_id" />
    </subclass>

    <subclass name="EntityUser" discriminator-value="entity">
        <many-to-one name="EntityProps" property-ref="login_cust_id" />     
    </subclass>
</class>

<class name="CustomerProps" Table="customer" >
  <id name="Id" column="cust_id">
    <generator class="assigned"/>
  </id>
  <property name="DisplayName" column="cust_mail_name"/>
  <property name="RecordChangeName" column="cust_lookup_name" />
</class>

<class name="EntityProps" Table="entity" >
  <id name="Id" column="entity_id">
    <generator class="assigned"/>
  </id>
  <property name="CompanyName"/>
</class>

解决方案3:使用连接到可更新视图的基于判别器的映射

最后一个选项是在DB中为包含login_sk字段的客户和实体表创建可更新视图。然后,您可以在每个子类中使用Join,因为您不需要property-ref

<class name="IUser" abstract="true" table="login">
    <id name="Id" column="login_sk">
        <generator class="identity"/>
    </id>
    <discriminator column="login_holder_type" not-null="true" type="System.String"/>

    <subclass name="CustomerUser" discriminator-value="Customer">
        <join table="customerView" >
          <key column="login_sk" />
          <property name="DisplayName" column="cust_mail_name"/>
          <property name="RecordChangeName" column="cust_lookup_name" />
        </join>
    </subclass>

    <subclass name="EntityUser" discriminator-value="Entity">
      <join table="entityView" >        
        <key column="login_sk" />
        <property name="CompanyName"/>
      </join>
    </subclass>
</class>