6

我正在使用棕地数据库,并尝试配置一个子类映射,该映射使用指定 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));
    }
}

传递的实例缺少填充的子类集合导致我寻找一个看起来更具体的检查器IParentInspector。不幸的是, Fluent NHibernate似乎没有对应的实现IParentInstanceIParentConvention或者IParentConventionAcceptance像它一样IJoinedSubclassInspector。虽然我可能可以在我这样做之前实现我自己的,但我想确保我没有在错误的树上吠叫。

这种子类ID调整甚至可能吗?我是否在我的地图或Fluent NHibernate Conventions 命名空间中遗漏了一些明显的东西?如何映射到具有与父 ID 不同的列/属性的连接子类?

4

1 回答 1

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 不支持。请在此处此处查看未完成的门票。已经进行了一些工作来添加此功能,这可以在 github上的这个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:基于鉴别器的映射与可更新视图的连接

最后一个选项是在数据库中为包含 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>
于 2013-03-11T23:31:05.953 回答