【问题标题】:Fluent NHibernate HasManyToMany with a discriminator column specifying relationship typeFluent NHibernate HasManyToMany,带有一个指定关系类型的鉴别器列
【发布时间】:2014-12-02 06:38:49
【问题描述】:

我正在使用 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

基本上,当在 RelationTable 中将 Jack 保存为 John 的新儿子时,我需要将 RelationType 填充为“A_IS_FATHER_OF_B_BOY”,这目前还没有发生。 指令 .Where("RelationType='A_IS_FATHER_OF_B_BOY'") 只对加载有效,对保存无效。

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

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

【问题讨论】:

  • 在你得到答案之前,我建议尽可能避免多对多。如果你喜欢阅读更多 herehere
  • @RadimKöhler,我已阅读您提供的链接。实际上,我确实将 RelationTable 映射为 2 个对 Person 的多对一引用(作为 PersonA 和 PersonB)。使用一对多(HasMany),那么您如何建议我在 Person 类中映射 Sons 和 Daughters(均为 List),同时考虑到上面的鉴别器值?谢谢。

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


【解决方案1】:

我想说,正如您在评论中指出的那样:

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

所以我眼中的配对对象应该是

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);

这必须是业务层 AddSon() 的一部分,也可以是 POCO 公共方法...

注意:我们也可以映射该关系的反向端......即使没有关系类型过滤:

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")
;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2012-02-08
    相关资源
    最近更新 更多