Fluent NHibernate:如何使用两侧的复合关键点映射M:N多对多

Fluent NHibernate:如何使用两侧的复合关键点映射M:N多对多,nhibernate,fluent-nhibernate,nhibernate-mapping,many-to-many,composite-key,Nhibernate,Fluent Nhibernate,Nhibernate Mapping,Many To Many,Composite Key,好的,这就是问题所在。它甚至不像那个想在PKs中用不同列数映射m:n的家伙那样疯狂 无论我做什么,无论我看哪里,似乎都没有方法链能够成功地映射这一点 我曾尝试将父列和子列合并,例如ParentColumn.ParentColumn.ChildColumn.ChildColumn-我认为这样做行不通,我是对的 试着用外国钥匙,但是运气不好。FNH仍然将一侧映射到单个键 更新: 我已尝试创建自定义密钥类型,但未成功 如果您选择接受您的挑战: 使用此表结构(可能使用自定义键类型)呈现最佳工作流畅映

好的,这就是问题所在。它甚至不像那个想在PKs中用不同列数映射m:n的家伙那样疯狂

无论我做什么,无论我看哪里,似乎都没有方法链能够成功地映射这一点

我曾尝试将父列和子列合并,例如ParentColumn.ParentColumn.ChildColumn.ChildColumn-我认为这样做行不通,我是对的

试着用外国钥匙,但是运气不好。FNH仍然将一侧映射到单个键

更新: 我已尝试创建自定义密钥类型,但未成功

如果您选择接受您的挑战: 使用此表结构(可能使用自定义键类型)呈现最佳工作流畅映射的代码,奖金归您所有


有人吗?

对您的问题的简短回答是Fluent还不能处理这种情况,您应该将其映射到.hbm.xml文件

很长的答案是,如果2个父表的复合键由4个单独的祖父母表GPA1、GPA2、GPB1、GPB2的外键组成,Fluent实际上可以做到这一点——在下面的示例中。在这种情况下,映射可能看起来像这样。。。但这有点骇客

//OBJECTS
public class GPA1
{
    public virtual long ID {get;set;}
}
public class GPA2
{
    public virtual long ID { get; set; }
}
public class GPB1
{
    public virtual long ID { get; set; }
}
public class GPB2
{
    public virtual long ID { get; set; }
}
public class M2M2ParentA
{
    public virtual GPA1 ID1A { get; set; }
    public virtual GPA2 ID2A { get; set; }
}
public class M2M2ParentB
{
    public virtual GPB1 ID1B { get; set; }
    public virtual GPB2 ID2B { get; set; }
}
public class M2M2Link
{
    public virtual M2M2ParentA LinkA { get; set; }
    public virtual M2M2ParentB LinkB { get; set; }

    public virtual GPA1 ID1A
    {
        get { return LinkA.ID1A; }
        set { LinkA.ID1A = value; }
    }
    public virtual GPA2 ID2A
    {
        get { return LinkA.ID2A; }
        set { LinkA.ID2A = value; }
    }
    public virtual GPB1 ID1B
    {
        get { return LinkB.ID1B; }
        set { LinkB.ID1B = value; }
    }
    public virtual GPB2 ID2B
    {
        get { return LinkB.ID2B; }
        set { LinkB.ID2B = value; }
    }
}
//FLUENT MAPPINGS
public class GPA1Map : ClassMap<GPA1>
{
    public GPA1Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPA2Map : ClassMap<GPA2>
{
    public GPA2Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPB1Map : ClassMap<GPB1>
{
    public GPB1Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPB2Map : ClassMap<GPB2>
{
    public GPB2Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class M2M2ParentAMap : ClassMap<M2M2ParentA>
{
    public M2M2ParentAMap()
    {
        Table("M2M2ParentA");

        CompositeId()
            .KeyReference(x => x.ID1A, "M2M2ParentAId1")
            .KeyReference(x => x.ID1A, "M2M2ParentAId2");
    }
}
public class M2M2ParentBMap : ClassMap<M2M2ParentB>
{
    public M2M2ParentBMap()
    {
        Table("M2M2ParentB");

        CompositeId()
            .KeyReference(x => x.ID1B, "M2M2ParentBId1")
            .KeyReference(x => x.ID1B, "M2M2ParentBId2");
    }
}
public class M2M2LinkMap : ClassMap<M2M2Link>
{
    public M2M2LinkMap()
    {
        Table("M2M2Link");

        CompositeId()
            .KeyReference(x => x.ID1A, "M2M2ParentA_Id1")
            .KeyReference(x => x.ID1B, "M2M2ParentA_Id2")
            .KeyReference(x => x.ID2A, "M2M2ParentB_Id1")
            .KeyReference(x => x.ID2B, "M2M2ParentB_Id2");
    }
}
在每个映射类中都应该有很多关系,但我很懒。如果您选择包含.hbm.xml文件,我建议在配置ISessionFactory时使用.ExportToc:\函数,您可以编辑fluent输出的hbm文件。这是一个很好的起点

嗯,,
-Danno

您的问题的简短答案是Fluent还不能处理这种情况,您应该将其映射到.hbm.xml文件

很长的答案是,如果2个父表的复合键由4个单独的祖父母表GPA1、GPA2、GPB1、GPB2的外键组成,Fluent实际上可以做到这一点——在下面的示例中。在这种情况下,映射可能看起来像这样。。。但这有点骇客

//OBJECTS
public class GPA1
{
    public virtual long ID {get;set;}
}
public class GPA2
{
    public virtual long ID { get; set; }
}
public class GPB1
{
    public virtual long ID { get; set; }
}
public class GPB2
{
    public virtual long ID { get; set; }
}
public class M2M2ParentA
{
    public virtual GPA1 ID1A { get; set; }
    public virtual GPA2 ID2A { get; set; }
}
public class M2M2ParentB
{
    public virtual GPB1 ID1B { get; set; }
    public virtual GPB2 ID2B { get; set; }
}
public class M2M2Link
{
    public virtual M2M2ParentA LinkA { get; set; }
    public virtual M2M2ParentB LinkB { get; set; }

    public virtual GPA1 ID1A
    {
        get { return LinkA.ID1A; }
        set { LinkA.ID1A = value; }
    }
    public virtual GPA2 ID2A
    {
        get { return LinkA.ID2A; }
        set { LinkA.ID2A = value; }
    }
    public virtual GPB1 ID1B
    {
        get { return LinkB.ID1B; }
        set { LinkB.ID1B = value; }
    }
    public virtual GPB2 ID2B
    {
        get { return LinkB.ID2B; }
        set { LinkB.ID2B = value; }
    }
}
//FLUENT MAPPINGS
public class GPA1Map : ClassMap<GPA1>
{
    public GPA1Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPA2Map : ClassMap<GPA2>
{
    public GPA2Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPB1Map : ClassMap<GPB1>
{
    public GPB1Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class GPB2Map : ClassMap<GPB2>
{
    public GPB2Map()
    {
        Table("GPA1");

        Id(x => x.ID, "id_column");
    }
}
public class M2M2ParentAMap : ClassMap<M2M2ParentA>
{
    public M2M2ParentAMap()
    {
        Table("M2M2ParentA");

        CompositeId()
            .KeyReference(x => x.ID1A, "M2M2ParentAId1")
            .KeyReference(x => x.ID1A, "M2M2ParentAId2");
    }
}
public class M2M2ParentBMap : ClassMap<M2M2ParentB>
{
    public M2M2ParentBMap()
    {
        Table("M2M2ParentB");

        CompositeId()
            .KeyReference(x => x.ID1B, "M2M2ParentBId1")
            .KeyReference(x => x.ID1B, "M2M2ParentBId2");
    }
}
public class M2M2LinkMap : ClassMap<M2M2Link>
{
    public M2M2LinkMap()
    {
        Table("M2M2Link");

        CompositeId()
            .KeyReference(x => x.ID1A, "M2M2ParentA_Id1")
            .KeyReference(x => x.ID1B, "M2M2ParentA_Id2")
            .KeyReference(x => x.ID2A, "M2M2ParentB_Id1")
            .KeyReference(x => x.ID2B, "M2M2ParentB_Id2");
    }
}
在每个映射类中都应该有很多关系,但我很懒。如果您选择包含.hbm.xml文件,我建议在配置ISessionFactory时使用.ExportToc:\函数,您可以编辑fluent输出的hbm文件。这是一个很好的起点

嗯,,
-Danno

如果FluentNHibernate当前无法映射此文件,则可以使用hbm.xml文件映射它

我还为这两个类的复合id使用了一个组件。这使得标识与实体分离,从而允许会话。获取新的M2ID 1,2。有关表示复合id的3种方法的讨论,请参阅,对于NHibernate和Hibernate也是如此

<class name="M2M2ParentA" table="M2M2ParentA">
    <composite-id name="Id" class="M2M2Id">
        <key-property name="Id1" />
        <key-property name="Id2" />
    </composite-id>
    <bag name="BList" table="M2M2Link" lazy="false" fetch="join" >
        <key>
            <column name="M2M2ParentAId1" />
            <column name="M2M2ParentAId2" />
        </key>
        <many-to-many class="M2M2ParentB" >
            <column name="M2M2ParentBId1" />
            <column name="M2M2ParentBId2" />
        </many-to-many>
    </bag>
</class>

<class name="M2M2ParentB" table="M2M2ParentB">
    <composite-id name="Id" class="M2M2Id">
        <key-property name="Id1" />
        <key-property name="Id2" />
    </composite-id>
    <bag name="AList" table="M2M2Link" lazy="false" fetch="join" inverse="true">
        <key>
            <column name="M2M2ParentBId1" />
            <column name="M2M2ParentBId2" />
        </key>
        <many-to-many class="M2M2ParentA" >
            <column name="M2M2ParentAId1" />
            <column name="M2M2ParentAId2" />
        </many-to-many>
    </bag>
</class>
还有我对你们课程的看法

public class M2M2ParentA
{
    public M2M2ParentA()
    {
        BList = new List<M2M2ParentB>();
    }
    public virtual M2M2Id Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<M2M2ParentB> BList { get; set; }
}

public class M2M2ParentB
{
    public M2M2ParentB()
    {
        AList = new List<M2M2ParentA>();
    }
    public virtual M2M2Id Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<M2M2ParentA> AList { get; set; }
}

public class M2M2Id
{
    public M2M2Id() {}
    public M2M2Id( int id1, int id2 )
    {
        Id1 = id1;
        Id2 = id2;
    }
    public virtual int Id1 { get; set; }
    public virtual int Id2 { get; set; }
    public override int GetHashCode()
    {
        return Id1.GetHashCode() + Id2.GetHashCode();
    }
    public override bool Equals( object obj )
    {
        M2M2Id other = obj as M2M2Id;
        return other != null && Id1 == other.Id1 && Id2 == other.Id2;
    }
}

如果FluentNHibernate当前无法映射此文件,则可以使用hbm.xml文件进行映射

我还为这两个类的复合id使用了一个组件。这使得标识与实体分离,从而允许会话。获取新的M2ID 1,2。有关表示复合id的3种方法的讨论,请参阅,对于NHibernate和Hibernate也是如此

<class name="M2M2ParentA" table="M2M2ParentA">
    <composite-id name="Id" class="M2M2Id">
        <key-property name="Id1" />
        <key-property name="Id2" />
    </composite-id>
    <bag name="BList" table="M2M2Link" lazy="false" fetch="join" >
        <key>
            <column name="M2M2ParentAId1" />
            <column name="M2M2ParentAId2" />
        </key>
        <many-to-many class="M2M2ParentB" >
            <column name="M2M2ParentBId1" />
            <column name="M2M2ParentBId2" />
        </many-to-many>
    </bag>
</class>

<class name="M2M2ParentB" table="M2M2ParentB">
    <composite-id name="Id" class="M2M2Id">
        <key-property name="Id1" />
        <key-property name="Id2" />
    </composite-id>
    <bag name="AList" table="M2M2Link" lazy="false" fetch="join" inverse="true">
        <key>
            <column name="M2M2ParentBId1" />
            <column name="M2M2ParentBId2" />
        </key>
        <many-to-many class="M2M2ParentA" >
            <column name="M2M2ParentAId1" />
            <column name="M2M2ParentAId2" />
        </many-to-many>
    </bag>
</class>
还有我对你们课程的看法

public class M2M2ParentA
{
    public M2M2ParentA()
    {
        BList = new List<M2M2ParentB>();
    }
    public virtual M2M2Id Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<M2M2ParentB> BList { get; set; }
}

public class M2M2ParentB
{
    public M2M2ParentB()
    {
        AList = new List<M2M2ParentA>();
    }
    public virtual M2M2Id Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<M2M2ParentA> AList { get; set; }
}

public class M2M2Id
{
    public M2M2Id() {}
    public M2M2Id( int id1, int id2 )
    {
        Id1 = id1;
        Id2 = id2;
    }
    public virtual int Id1 { get; set; }
    public virtual int Id2 { get; set; }
    public override int GetHashCode()
    {
        return Id1.GetHashCode() + Id2.GetHashCode();
    }
    public override bool Equals( object obj )
    {
        M2M2Id other = obj as M2M2Id;
        return other != null && Id1 == other.Id1 && Id2 == other.Id2;
    }
}

我在google代码库中看到一个旧的补丁提交,说它添加了ParentKeyColumns和ChildKeyColumns,以及当前github repo中中止的实现。HMMMMI在google代码库中看到一个旧的补丁提交,说它添加了ParentKeyColumns和ChildKeyColumns,以及当前github repo中中止的实现。hmmmmm@Danno,如果这个问题涉及到绘制一个在现实世界中可能永远看不到的人造结构,而不是我的问题中假设的非常可能(尽管设计糟糕)的场景,那将有所帮助-@丹诺,如果你做得更多,陈述显而易见的情况,提出一个完全不相关的场景,我可能会接受这个答案。也许通过发布你提到的hbm?@Danno,如果问题涉及到绘制一个在现实世界中可能永远看不到的人造结构,而不是我问题中提出的非常可能的、尽管设计拙劣的场景,这会有所帮助-@丹诺,如果你做得更多,陈述显而易见的情况,提出一个完全不相关的场景,我可能会接受这个答案。也许通过发布你提到的hbm?@Lachlan,我将启动该项目并在今晚确认。thanks@Lachlan,我已经被其他事情掩盖了,但看看你的代码,我相信我能用它工作。非常感谢。@Lachlan,我将启动该项目并在今晚确认。thanks@Lachlan,我已经被其他事情掩盖了,但看看你的代码,我相信我能用它工作。非常感谢。