流畅的NHibernate HasManyToMany,带有指定关系类型的鉴别器列

时间:2014-12-02 06:38:50

标签: c# nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我正在使用Fluent NHibernate,我试图映射多个属性,只是绕过连接表。棘手的是,连接表有一个列,用于确定它的关系类型。

出于这个问题的目的,让我们说我有个人表和关系表。

PersonTable (PersonId, Name, etc)
RelationTable (RelationType, PersonIdA, PersonIdB)

我想在Person类中为每种类型的关系引入一个集合属性,例如:儿子,女儿等等。

HasManyToMany<Person>(x => x.Sons)
    .Table("RelationTable")
    .ParentKeyColumn("PersonIdA")
    .ChildKeyColumn("PersonIdB")
    .Where("RelationType='A_IS_FATHER_OF_B_BOY'");

HasManyToMany<Person>(x => x.Daughters)
    .Table("RelationTable")
    .ParentKeyColumn("PersonIdA")
    .ChildKeyColumn("PersonIdB")
    .Where("RelationType='A_IS_FATHER_OF_B_GIRL'");

以上映射用于从数据库读取,但不用于插入,例如:

Person john = PersonDAO.GetByName("John"); // the Sons and Daughters are loaded fine based on mappings above

john.Sons.Add(new Person("Jack"));  // let's add a new son
PersonDAO.Save(john);               // this fails because RelationType is null

基本上,在将Jack作为John的新儿子保存在RelationTable中时,我需要使用&#34; A_IS_FATHER_OF_B_BOY&#34;填充RelationType,这当前没有发生。 指令.Where(&#34; RelationType =&#39; A_IS_FATHER_OF_B_BOY&#39;&#34;)仅对加载有效,但不能用于保存。

有什么想法吗?我认为这有点类似于子类的Discriminator属性。

任何帮助表示赞赏。感谢。

1 个答案:

答案 0 :(得分:1)

我会说,正如你在评论中指出的那样:

  

实际上我确实将RelationTable映射为2个 many-to-one 对Person的引用(作为PersonA和PersonB)。使用 one-to-many (HasMany),您如何建议我在Person类中映射Sons和Daughters(两个List<Person>),同时考虑上面的鉴别器值

所以我眼中的配对对象是

public class PersonRelation
{
    // the pairing table must contain the key column, surrogated ID
    public virtual int Id { get; protected set; } // this is a must. 

    public virtual Person Parent { get; set; }
    public virtual Person Child { get; set; }
    public virtual string RelationType { get; set; }
}

这张桌子必须有钥匙。只需向SQL Server注入一些IDENTITY列,但有一些带有代理(业务域无关)密钥。

这是我们的Person实体

public class Person
{
    IList<PersonRelation> _sons;
    IList<PersonRelation> _daughters;
    ..,
    public virtual IList<PersonRelation> Sons 
    {
        get { return _sons ?? (_sons = new List<PersonRelation>()); }
        set { _sons = value; }
    }
    public virtual IList<PersonRelation> Daughters
    {
        get { return _daughters?? (_daughters= new List<PersonRelation>()); }
        set { _daughters= value; }
    }
}

Sons 的映射(Daughters会相同)

HasMany<PersonRelation>(x => x.Sons)
    // .Table("RelationTable") // not needed - part of PersonRleation mapping
    .KeyColumn("PersonIdA")
    .Where("RelationType='A_IS_FATHER_OF_B_BOY'")
    .Inverse()
    .Cascade.AllDeleteOrphan() 
;

如果我们总是保证,那么在添加Son时,我们也可以正确设置RelationType

var parent = ...; // new, loaded
var child  = ...; // new, loaded

var relation = new PersonRelation
{
    Parent = parent;
    Child  = child;
    RelationType = "A_IS_FATHER_OF_B_BOY";
};

parnet.Sons.Add(relation);

这必须是Businese图层AddSon()的一部分,或者它可能是POCO公共方法......

注意:我们也可以映射该关系的反向结束...即使没有relationType过滤:

public class Person
{
    ... as above
    public virtual IList<PersonRelation> Parents { get; set; }


HasMany<PersonRelation>(x => x.Parents)
    // instead of this
    // .KeyColumn("PersonIdA")
    // we need this column
    .KeyColumn("PersonIdB")
;