2011-03-02 9 views
2

私はマッピングしたい次の簡単なエンティティ:以下のマッピングでNHibernateの複製列

public class AnimalsOwner 
{ 
    public AnimalsOwner() 
    { 
     Cats = new List<Cat>(); 
     Dogs = new List<Dog>(); 
    } 

    public virtual int Id { get; set; } 

    public virtual IList<Cat> Cats { get; set; } 

    public virtual IList<Dog> Dogs { get; set; } 
} 

public abstract class Animal 
{ 
    public virtual int Id { get; set; } 

    public virtual AnimalsOwner AnimalsOwner { get; set; } 
} 

public class Dog : Animal 
{ 
    public virtual string DogsProperty { get; set; } 
} 

public class Cat : Animal 
{ 
    public virtual string CatsProperty { get; set; } 
} 

public OwnerMapping() 
    { 
     this.Table("Owners"); 
     Id(x => x.Id) 
      .GeneratedBy.Native(); 

     HasMany(x => x.Cats).AsBag().Cascade.SaveUpdate(); 
     HasMany(x => x.Dogs).AsBag().Cascade.SaveUpdate(); 
    } 
} 

public class AnimalMapping : ClassMap<Animal> 
{ 
    public AnimalMapping() 
    { 
     this.Table("Animals"); 
     Id(x => x.Id).GeneratedBy.Native(); 

     References(x => x.AnimalsOwner).Not.Nullable(); 
    } 
} 

public class DogMap : SubclassMap<Dog> 
{ 
    public DogMap() 
    { 
     this.Table("Dogs"); 
     this.KeyColumn("AnimalId"); 
     Map(x => x.DogsProperty); 
    } 
} 

public class CatMap : SubclassMap<Cat> 
{ 
    public CatMap() 
    { 
     this.Table("Cats"); 
     this.KeyColumn("AnimalId"); 
     Map(x => x.CatsProperty); 
    } 
} 
すべてが正常に動作し、このようなマッピングでは

が、生成されたスキーマは、次のようになります。

Db schema

そして、そのようなコード:

var owner = new AnimalsOwner(); 
        owner.Cats.Add(new Cat() 
        { 
         AnimalsOwner = owner, 
         CatsProperty = "cat" 
        }); 

カラムOwnderIdの3つのテーブル(動物、猫、犬)すべてに挿入を行います。しかし、それは動物のテーブルだけでは十分ではありませんか?はいの場合はどのように達成するのですか? NHibernateが期待どおりに動作するなら、なぜ彼はそのような重複をしていますか?

答えて

3

私はこれをtable-per-class戦略を使用してマップし、パブリックコレクションをタイプ別にフィルタリングします。このデータベース構造は、作業するのがはるかに簡単で、照会はより効率的です。

public class AnimalMapping : ClassMap<Animal> 
{ 
    public AnimalMapping() 
    { 
     Table("Animals"); 
     Id(x => x.Id).GeneratedBy.Native();  
     References(x => x.AnimalsOwner); 
     DiscriminateSubClassesOnColumn("AnimalType"); 
    } 
} 

public class DogMap : SubclassMap<Dog> 
{ 
    public DogMap() 
    { 
     DiscriminatorValue("DOG"); 
     Map(x => x.DogsProperty); 
    } 
} 

public class CatMap : SubclassMap<Cat> 
{ 
    public CatMap() 
    { 
     DiscriminatorValue("CAT"); 
     Map(x => x.CatsProperty); 
    } 
} 

犬や猫コレクションは種類によってプライベートメンバーやフィルタリングなどの動物コレクションをマッピングすることにより、公開することができます。

public class AnimalsOwner 
{ 
    private IList<Animal> _animals; 

    public AnimalsOwner() 
    { 
     _animals = new List<Animal>(); 
    } 

    public virtual int Id { get; set; } 

    public virtual IEnumerable<Animal> Animals { get { return _animals; } } 

    public virtual IEnumerable<Cat> Cats { get { return _animals.OfType<Cat>(); } } 

    public virtual IEnumerable<Dog> Dogs { get { return _animals.OfType<Dog>(); } } 

    public virtual void AddAnimal(Animal animal) 
    { 
     if (!_animals.Contains(animal)) 
     { 
      animal.AnimalsOwner = this; 
      _animals.Add(animal); 
     } 
    } 

    public virtual void RemoveAnimal(Animal animal) 
    { 
     if (_animals.Contains(animal)) 
     { 
      animal.AnimalsOwner = null; 
      _animals.Remove(animal); 
     | 
    } 
} 

このクラスのマッピングは次のようになります。

public OwnerMapping() 
    { 
     this.Table("Owners"); 
     Id(x => x.Id).GeneratedBy.Native(); 

     HasMany(x => x.Animals.AsBag.Cascade.AllDeleteOrphan() 
      .Inverse().LazyLoad() 
      .Access.CamelCaseField(Prefix.Underscore); 
    } 
} 

猫を追加するコードは次のようになります:

var owner = new AnimalsOwner(); 
owner.AddAnimal(new Cat() 
       { 
        CatsProperty = "cat" 
       }); 
0

所有者マッピングでHasMany CatsとDogsが定義されているため(オーナークラスのCat & Dogコレクション)、重複が発生しています。おそらくあなたが本当に望むのは、所有者クラス(個々に犬と猫ではない)と所有者マッピングのHasMany Animalsのみのコレクションです。

+1

いいえ、その意図は本当に別のコレクションを持っています – Sly