6

ブラウンフィールドデータベースを使用していて、指定されたIDの列以外の列でそのサブクラスに結合するサブクラスマップを構成しようとしています。loginテーブルには、IDとして使用したい主キー列がlogin_skあります。1つの列を介して2つのテーブルに結合しlogin_cust_idます(より楽しくするために、隣接するテーブルの対応する列の名前は異なります)。login_cust_idUserMapの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 NHibernateIParentInstanceには、に対応する実装がないIParentConventionようIParentConventionAcceptanceですIJoinedSubclassInspector。おそらく自分で実装する前に実装することはできますが、間違ったツリーを吠えないようにしたかったのです。

この種のサブクラスIDの調整も可能ですか?マップまたはFluentNHibernateConventions名前空間のいずれかに明らかな何かが欠けていますか?親のIDとは異なる列/プロパティを持つ結合されたサブクラスにマップするにはどうすればよいですか?

4

1 に答える 1

3

あなたの問題に対する 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のこのフォークで確認できます。

解決策 2: 多対 1 の識別子ベースのマッピング

もう 1 つのオプションは、ディスクリミネータ ベースのマッピングを引き続き使用することですが、many-to-one各サブクラス内でマッピングを使用することです。これにより、プロパティ参照を使用して外部キーに結合できます。これには、顧客テーブルとエンティティ テーブルのすべてのプロパティに対して個別のクラスが必要になるという欠点がありますが、実行可能なソリューションです。

<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 フィールドを含む顧客およびエンティティ テーブルの DB に更新可能なビューを作成することです。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 に答える