2009-03-17 15 views
26

次のシナリオでは、Fluent NHibernateを使用して型階層をデータベーススキーマにマップします。Fluent NHibernateでの継承マッピング

私はItemSubItemクラスは抽象的であるNHibernateは2.0


型階層

public abstract class Item 
{ 
    public virtual int ItemId { get; set; } 
    public virtual string ItemType { get; set; } 
    public virtual string FieldA { get; set; } 
} 

public abstract class SubItem : Item 
{ 
    public virtual string FieldB { get; set; } 
} 

public class ConcreteItemX : SubItem 
{ 
    public virtual string FieldC { get; set; } 
} 

public class ConcreteItemY : Item 
{ 
    public virtual string FieldD { get; set; } 
} 

See image

を使用しています。


データベーススキーマ

 
+----------+ +---------------+ +---------------+ 
| Item  | | ConcreteItemX | | ConcreteItemY | 
+==========+ +===============+ +===============+ 
| ItemId | | ItemId  | | ItemId  | 
| ItemType | | FieldC  | | FieldD  | 
| FieldA | +---------------+ +---------------+ 
| FieldB | 
+----------+ 

See image

ItemTypeフィールドには、コンクリートの種類を決定します。

ConcreteItemXテーブルの各レコードには、対応するレコードがItemテーブルに1つあります。 ConcreteItemYテーブルの場合も同様です。

FieldBは、アイテムタイプがConcreteItemYの場合は常にnullです。


マッピング(これまで)

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     WithTable("Item"); 
     Id(x => x.ItemId, "ItemId"); 
     Map(x => x.FieldA, "FieldA"); 

     JoinedSubClass<ConcreteItemX>("ItemId", MapConcreteItemX); 
     JoinedSubClass<ConcreteItemY>("ItemId", MapConcreteItemY); 
    } 

    private static void MapConcreteItemX(JoinedSubClassPart<ConcreteItemX> part) 
    { 
     part.WithTableName("ConcreteItemX"); 
     part.Map(x => x.FieldC, "FieldC"); 
    } 

    private static void MapConcreteItemY(JoinedSubClassPart<ConcreteItemY> part) 
    { 
     part.WithTableName("ConcreteItemX"); 
     part.Map(x => x.FieldD, "FieldD"); 
    } 
} 

FieldBがマッピングされていません。


質問私は流暢NHibernateはを使用してSubItemクラスのFieldBプロパティをマッピングするにはどうすればよい

DiscriminateSubClassesOnColumnには、ItemTypeフィールドを使用する方法はありますか?


補遺

私はのhbm.xmlファイルを使用して所望の結果を達成することができる午前:

<class name="Item" table="Item"> 

    <id name="ItemId" type="Int32" column="ItemId"> 
    <generator class="native"/> 
    </id> 

    <discriminator column="ItemType" type="string"/> 

    <property name="FieldA" column="FieldA"/> 

    <subclass name="ConcreteItemX" discriminator-value="ConcreteItemX"> 
    <!-- Note the FieldB mapping here --> 
    <property name="FieldB" column="FieldB"/> 
    <join table="ConcreteItemX"> 
     <key column="ItemId"/> 
     <property name="FieldC" column="FieldC"/> 
    </join> 
    </subclass> 

    <subclass name="ConcreteItemY" discriminator-value="ConcreteItemY"> 
    <join table="ConcreteItemY"> 
     <key column="ItemId"/> 
     <property name="FieldD" column="FieldD"/> 
    </join> 
    </subclass> 

</class> 

は、どのように私は流暢NHibernateはを使用して上記のマッピングを達成するのですか?

Fluent NHibernateを使用して、クラスごとのテーブル階層とtable-per-subclassを混在させることはできますか?

+0

これはコミュニティウィキとマークされている理由は何ですか?いずれにしても、使用しているマッピング戦略を明確にすることはできますか? JoinedSubClassPartは、サブクラスごとのパターンを意味しますが、具体的な項目がItemテーブルに保持されているとは、クラスあたりのテーブルのパターンを意味します。 –

+0

コミュニティのwiki設定を変更する方法がわかりません。 FieldBを無視すると、table-per-subclassを使用できます。 FieldBの存在は私にいくつかの混乱を引き起こします。それは2つの戦略が混在しているようです。 ConcreteItemX型はSubItemからFieldBを継承します。 FieldBはItemテーブルに保持されます。 –

答えて

1

私はそれが正しいとは確信していませんが、うまくいくかもしれません...誰かがこれをもっときれいにすることができれば、私はそれを見たいと思っています(これは面白い問題です) 。あなたが与えた正確なクラス定義を使用して

、ここでのマッピングは、次のとおりです。

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     Id(x => x.ItemId); 
     Map(x => x.ItemType); 
     Map(x => x.FieldA); 

     AddPart(new ConcreteItemYMap()); 
    } 
} 

public class SubItemMap : ClassMap<SubItem> 
{ 
    public SubItemMap() 
    { 
     WithTable("Item"); 

     // Get the base map and "inherit" the mapping parts 
     ItemMap baseMap = new ItemMap(); 
     foreach (IMappingPart part in baseMap.Parts) 
     { 
      // Skip any sub class parts... yes this is ugly 
      // Side note to anyone reading this that might know: 
      // Can you use GetType().IsSubClassOf($GenericClass$) 
      // without actually specifying the generic argument such 
      // that it will return true for all subclasses, regardless 
      // of the generic type? 
      if (part.GetType().BaseType.Name == "JoinedSubClassPart`1") 
       continue; 
      AddPart(part); 
     } 
     Map(x => x.FieldB); 
     AddPart(new ConcreteItemXMap()); 
    } 
} 

public class ConcreteItemXMap : JoinedSubClassPart<ConcreteItemX> 
{ 
    public ConcreteItemXMap() 
     : base("ItemId") 
    { 
     WithTableName("ConcreteItemX"); 
     Map(x => x.FieldC); 
    } 
} 

public class ConcreteItemYMap : JoinedSubClassPart<ConcreteItemY> 
{ 
    public ConcreteItemYMap() 
     : base("ItemId") 
    { 
     WithTableName("ConcreteItemY"); 
     Map(x => x.FieldD); 
    } 
} 

は、これらのマッピングは(いくつかの無関係なデータを明確にするため取り除か)のように2つのhbm.xmlファイルを生成します。

<class name="Item" table="`Item`"> 
    <id name="ItemId" column="ItemId" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="FieldA" type="String"> 
     <column name="FieldA" /> 
    </property> 
    <property name="ItemType" type="String"> 
     <column name="ItemType" /> 
    </property> 
    <joined-subclass name="ConcreteItemY" table="ConcreteItemY"> 
     <key column="ItemId" /> 
     <property name="FieldD"> 
     <column name="FieldD" /> 
     </property> 
    </joined-subclass> 
    </class> 

    <class name="SubItem" table="Item"> 
    <id name="ItemId" column="ItemId" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="FieldB" type="String"> 
     <column name="FieldB" /> 
    </property> 
    <property name="ItemType" type="String"> 
     <column name="ItemType" /> 
    </property> 
    <property name="FieldA" type="String"> 
     <column name="FieldA" /> 
    </property> 
    <joined-subclass name="ConcreteItemX" table="ConcreteItemX"> 
     <key column="ItemId" /> 
     <property name="FieldC"> 
     <column name="FieldC" /> 
     </property> 
    </joined-subclass> 
    </class> 

それは醜いですが、使用可能なマッピングファイルが生成されているようで、Fluentです! :/ あなたが望むものを得るために、アイデアをもう少し微調整することができます。

1

コードの行:if (part.GetType().BaseType.Name == "JoinedSubClassPart1")次のように を書き換えることができます:あなたは、あなたのスーパークラスマップのコンストラクタにこれを追加することができます

public static class DataObjectBaseExtension 
{ 
    public static void DefaultMap<T>(this ClassMap<T> DDL) where T : IUserAuditable 
    { 
     DDL.Map(p => p.AddedUser).Column("AddedUser"); 
     DDL.Map(p => p.UpdatedUser).Column("UpdatedUser"); 
    } 
} 

part.GetType().BaseType.IsGenericType && part.GetType().BaseType.GetGenericTypeDefinition() == typeof(JoinedSubClassPart<>) 
1

は、これは私が私の継承の問題を解決する方法であります:

internal class PatientMap : ClassMap<Patient> 
{ 
    public PatientMap() 
    { 
     Id(p => p.GUID).Column("GUID"); 
     Map(p => p.LocalIdentifier).Not.Nullable(); 
     Map(p => p.DateOfBirth).Not.Nullable(); 
     References(p => p.Sex).Column("RVSexGUID"); 
     References(p => p.Ethnicity).Column("RVEthnicityGUID"); 

     this.DefaultMap(); 
    } 


} 
+0

素晴らしい、ありがとう! – vondip

26

これは本当に古いですが、私は知っていますあなたが最初に望んでいた正確なマッピングを生成するように流暢に設定するのはとても簡単です。答えを探すときに私はこのポストを見つけたので、私はそれを投稿すると思った。

あなたは自分のサブクラスへの参照せずに、基本クラスのためのあなたのClassMapを作成します。

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     this.Table("Item"); 
     this.DiscriminateSubClassesOnColumn("ItemType"); 
     this.Id(x => x.ItemId, "ItemId"); 
     this.Map(x => x.FieldA, "FieldA"); 
    } 
} 

次に、このようなあなたの抽象サブクラスにマップ:

public class SubItemMap: SubclassMap<SubItemMap> 
{ 
    public SubItemMap() 
    { 
     this.Map(x => x.FieldB); 
    } 
} 

が続いそうのようなあなたの具象サブクラスをマップ:

public class ConcreteItemXMap : SubclassMap<ConcreteItemX> 
{ 
    public ConcretItemXMap() 
    { 
     this.Join("ConcreteItemX", x => 
     { 
      x.KeyColumn("ItemID"); 
      x.Map("FieldC") 
     }); 
    } 
} 

これが他の誰かがこのタイプを探すのに役立ちます流暢でマッピングする。

+0

ニース!正確に私が必要としたもの。 – jweyrich

関連する問題