流利的NHibernate:如何映射M:N多对多的复合键在两边 [英] Fluent NHibernate: How to Map M:N many-to-many with composite keys on both sides

查看:176
本文介绍了流利的NHibernate:如何映射M:N多对多的复合键在两边的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,这是问题所在。它甚至不像那些想在地图上用不同列数的m:n地图的人那么疯狂。无论我做什么或者在哪里看,没有方法链会导致这个成功的映射。



我已经尝试在父和子列上加倍,例如ParentColumn()。ParentColumn()。ChildColumn()。ChildColumn( ) - 没有'认为它会工作,我是正确的。



尝试使用ForeignKeyConstraintNames没有运气。仍然FNH映射一边到一个单一的关键。



问题域名http://www.freeimagehosting.net/uploads/349e4acfe3.png

  public部分类M2M2ParentAMap:ClassMap< M2M2ParentA> 
{
public M2M2ParentAMap()
{
Table(`M2M2ParentA`);
架构(`dbo`);
CompositeId().KeyProperty(x => x.M2M2ParentAId1,M2M2ParentAId1).KeyProperty(x => x.M2M2ParentAId2,M2M2ParentAId2);
HasManyToMany(x => x.M2M2ParentB).Schema(`dbo`)
.ForeignKeyConstraintNames(FK_M2M2Link_M2M2ParentA,FK_M2M2Link_M2M2ParentB);
}
}



public partial class M2M2ParentBMap:ClassMap< M2M2ParentB>
{
public M2M2ParentBMap()
{
Table(`M2M2ParentB`);
架构(`dbo`);
CompositeId()。KeyProperty(x => x.M2M2ParentBId1,M2M2ParentBId1).KeyProperty(x => x.M2M2ParentBId2,M2M2ParentBId2);
HasManyToMany(x => x.M2M2ParentA)
.Schema(`dbo`)。ForeignKeyConstraintNames(FK_M2M2Link_M2M2ParentB,FK_M2M2Link_M2M2ParentA);
}
}



public partial class M2M2LinkMap:ClassMap< M2M2Link>
{
public M2M2LinkMap()
{
Table(`M2M2Link`);
架构(`dbo`);
CompositeId()
.KeyProperty(x => x.M2M2ParentA_Id1,M2M2ParentA_Id1)
.KeyProperty(x => x.M2M2ParentA_Id2,M2M2ParentA_Id2)
.KeyProperty(x => x.M2M2ParentB_Id1,M2M2ParentB_Id1);
.KeyProperty(x => x.M2M2ParentB_Id2,M2M2ParentB_Id2);

参考文献(x => x.M2M2ParentA).Columns(`M2M2ParentA_Id1`,`M2M2ParentA_Id2)。Cascade.All();
引用(x => x.M2M2ParentB).Columns(`M2M2ParentB_Id1`,`M2M2ParentB_Id2)。Cascade.All();



$ b错误:
外键(FK_M2M2Link_M2M2ParentB:M2M2ParentAToM2M2ParentB [M2M2ParentB_id]))必须与引用的主键具有相同的列数(M2M2ParentB [M2M2ParentBId1,M2M2ParentBId2])





  public partial class M2M2ParentAMap:ClassMap< M2M2ParentA> 
{
public M2M2ParentAMap()
{
Table(`M2M2ParentA`);
架构(`dbo`);
CompositeId()
.KeyProperty(x => x.M2M2ParentAId1,M2M2ParentAId1)
.KeyProperty(x => x.M2M2ParentAId2,M2M2ParentAId2);

HasManyToMany(x => x.M2M2ParentB)
.Schema(`dbo`)
.Table(`M2M2Link`)
.ParentKeyColumn (`M2M2ParentA_Id1`)
.ParentKeyColumn(`M2M2ParentA_Id2`)
.ChildKeyColumn(`M2M2ParentB_Id1`)
.ChildKeyColumn(`M2M2ParentB_Id2`);
}
}


public partial class M2M2ParentBMap:ClassMap< M2M2ParentB>
{
public M2M2ParentBMap()
{
Table(`M2M2ParentB`);
架构(`dbo`);
CompositeId()
.KeyProperty(x => x.M2M2ParentBId1,M2M2ParentBId1)
.KeyProperty(x => x.M2M2ParentBId2,M2M2ParentBId2);

HasManyToMany(x => x.M2M2ParentA)
.Schema(`dbo`)
.Table(`M2M2Link`)
.ParentKeyColumn (`M2M2ParentB_Id1`)
.ParentKeyColumn(`M2M2ParentB_Id2`)
.ChildKeyColumn(`M2M2ParentA_Id1`)
.ChildKeyColumn(`M2M2ParentA_Id2`);
}
}



public partial class M2M2LinkMap:ClassMap< M2M2Link>
{
public M2M2LinkMap()
{
Table(`M2M2Link`);
架构(`dbo`);
CompositeId()
.KeyProperty(x => x.M2M2ParentA_Id1,M2M2ParentA_Id1)
.KeyProperty(x => x.M2M2ParentA_Id2,M2M2ParentA_Id2)
.KeyProperty(x => x.M2M2ParentB_Id1,M2M2ParentB_Id1);
.KeyProperty(x => x.M2M2ParentB_Id2,M2M2ParentB_Id2);

引用(x => x.M2M2ParentA)
.Columns(`M2M2ParentA_Id1`,`M2M2ParentA_Id2`)。Cascade.All();

引用(x => x.M2M2ParentB)
.Columns(`M2M2ParentB_Id1`,`M2M2ParentB_Id2)。Cascade.All();


$ b错误:
外键(M2M2ParentBId1) ,M2M2ParentBId2])

DDL

  CREATE TABLE [dbo]。[M2M2ParentA]([M2M2ParentAId1] [int] NOT NULL,
[M2M2ParentAId2] [int] NOT NULL,
CONSTRAINT [PK_M2M2ParentA] PRIMARY KEY CLUSTERED([M2M2ParentAId1] ASC,[M2M2ParentAId2] ASC))

CREATE TABLE [dbo]。[M2M2ParentB]([M2M2ParentBId1] [int] NOT NULL,
[M2M2ParentBId2] [int] NOT NULL,
CONSTRAINT [PK_M2M2ParentB] PRIMARY KEY CLUSTERED([M2M2ParentBId1] ASC,[M2M2ParentBId2] ASC))


CREATE TABLE [dbo] 。[M2M2Link]([M2M2ParentA_Id1] [int] NOT NULL,
[M2M2ParentA_Id2] [int] NOT NULL,
[M2M2ParentA_Id1] ASC,[M2M2ParentA_Id2] ASC,[M2M2ParentB_Id1] ASC,[M2M2ParentB_Id1] [INT] NOT NULL,
[M2M2ParentB_Id2] [int] NOT NULL,
CONSTRAINT [PK_M2M2Link] [PRIMARY KEY CLUSTERED] M2M2ParentB_Id2] ASC))



ALTER TABLE [dbo]。[M2M2Link]
WITH CHECK
ADD CONSTRAINT [FK_M2M2Link_M2M2ParentA] FOREIGN KEY([M2M2ParentA_Id1 ],[M2M2ParentA_Id2])参考[dbo]。[M2M2ParentA]([M2M2ParentAId1],
[M2M2ParentAId2])
ALTER TABLE [dbo]。[M2M2Link]
CHECK CONSTRAINT [FK_M2M2Link_M2M2ParentA]
ALTER TABLE [dbo]。[M2M2Link]
WITH CHECK
ADD CONSTRAINT [FK_M2M2Link_M2M2ParentB] FOREIGN KEY([M2M2ParentB_Id1],[M2M2ParentB_Id2])参考[dbo]。[M2M2ParentB]([M2M2ParentBId1] ,
[M2M2ParentBId2])
ALTER TABLE [dbo]。[M2M2Link]
CHECK CONSTRAINT [FK_M2M2Link_M2M2ParentB]

更新:
我已经尝试创建一个自定义的键类型,但没有成功。



如果您选择接受它, / h2>

使用此表结构的最佳工作流畅映射的代码,可能使用自定义键类型,赏金是您的。



任何人?

解决方案如果FluentNHibernate目前无法映射这个,那么你可以使用hbm.xml文件映射它。



我还使用了一个组件作为这两个类的组合id。这使得身份与实体分离,从而允许 session.Get (新M2M2Id(1,2))。请参阅这个答案讨论三种方法来表示复合id(它是对于NHibernate和Hibernate来说是一样的)。

 < class name =M2M2ParentAtable =M2M2ParentA> 
< composite-id name =Idclass =M2M2Id>
< key-property name =Id1/>
< key-property name =Id2/>
< / composite-id>
< bag name =BListtable =M2M2Linklazy =falsefetch =join>
< key>
< column name =M2M2ParentAId1/>
< column name =M2M2ParentAId2/>
< / key>
< column name =M2M2ParentBId1/>
< column name =M2M2ParentBId2/>
>
< / bag>
< / class>

< class name =M2M2ParentBtable =M2M2ParentB>
< composite-id name =Idclass =M2M2Id>
< key-property name =Id1/>
< key-property name =Id2/>
< / composite-id>
< bag name =AListtable =M2M2Linklazy =falsefetch =joininverse =true>
< key>
< column name =M2M2ParentBId1/>
< column name =M2M2ParentBId2/>
< / key>
< column name =M2M2ParentAId1/>
< column name =M2M2ParentAId2/>
>
< / bag>
< / class>

以及我的版本的类。

<$ (); b














$
}
public virtual M2M2Id Id {get;组; }
public virtual string Name {get;组; }
公共虚拟IList< M2M2ParentB> BList {get;组; ();}

$ b public class M2M2ParentB
{
public M2M2ParentB()
{
AList = new List< M2M2ParentA>
}
public virtual M2M2Id Id {get;组; }
public virtual string Name {get;组; }
公共虚拟IList< M2M2ParentA> AList {get;组; }

$ b $ public class M2M2Id
{
public M2M2Id(){}
public M2M2Id(int id1,int id2)
{
Id1 = id1;
Id2 = id2;
}
public virtual int Id1 {get;组; }
public virtual int Id2 {get;组; }
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;
}
}


OK, so here is the problem. Its not even as crazy as the guy who wants to map m:n with different column counts in his PKs.

No matter what I do or where I look there seems to be no method chain that will result in a successful mapping of this.

I have tried doubling up on the Parent and Child columns, eg ParentColumn("").ParentColumn("").ChildColumn("").ChildColumn("") - didnt' think it would work and I was right.

Tried just using ForeignKeyConstraintNames no luck. Still FNH is mapping one side to a single key.

problem domain http://www.freeimagehosting.net/uploads/349e4acfe3.png

        public partial class M2M2ParentAMap : ClassMap<M2M2ParentA>
        {
            public M2M2ParentAMap()
            {
                Table("`M2M2ParentA`");
                Schema("`dbo`");
                CompositeId().KeyProperty( x => x.M2M2ParentAId1, "`M2M2ParentAId1`" ).KeyProperty( x => x.M2M2ParentAId2, "`M2M2ParentAId2`" );
                HasManyToMany(x => x.M2M2ParentB).Schema("`dbo`")
                    .ForeignKeyConstraintNames("FK_M2M2Link_M2M2ParentA", "FK_M2M2Link_M2M2ParentB");
            }
        }



        public partial class M2M2ParentBMap : ClassMap<M2M2ParentB>
        {
            public M2M2ParentBMap()
            {
                Table("`M2M2ParentB`");
                Schema("`dbo`");
                CompositeId().KeyProperty( x => x.M2M2ParentBId1, "`M2M2ParentBId1`" ).KeyProperty( x => x.M2M2ParentBId2, "`M2M2ParentBId2`" );
                HasManyToMany(x => x.M2M2ParentA)
                    .Schema("`dbo`").ForeignKeyConstraintNames("FK_M2M2Link_M2M2ParentB", "FK_M2M2Link_M2M2ParentA");
            }
        }



        public partial class M2M2LinkMap : ClassMap<M2M2Link>
        {
            public M2M2LinkMap()
            {
                Table("`M2M2Link`");
                Schema("`dbo`");
                CompositeId()
                    .KeyProperty( x => x.M2M2ParentA_Id1, "`M2M2ParentA_Id1`" )
                    .KeyProperty( x => x.M2M2ParentA_Id2, "`M2M2ParentA_Id2`" )
                    .KeyProperty( x => x.M2M2ParentB_Id1, "`M2M2ParentB_Id1`" )
                    .KeyProperty( x => x.M2M2ParentB_Id2, "`M2M2ParentB_Id2`" );

                References(x => x.M2M2ParentA).Columns("`M2M2ParentA_Id1`","`M2M2ParentA_Id2`").Cascade.All();
                References(x => x.M2M2ParentB).Columns("`M2M2ParentB_Id1`","`M2M2ParentB_Id2`").Cascade.All();
            }
        }


ERROR:
Foreign key (FK_M2M2Link_M2M2ParentB:M2M2ParentAToM2M2ParentB [M2M2ParentB_id])) must have same number of columns as the referenced primary key (M2M2ParentB [M2M2ParentBId1, M2M2ParentBId2])

AND

        public partial class M2M2ParentAMap : ClassMap<M2M2ParentA>
        {
            public M2M2ParentAMap()
            {
                Table("`M2M2ParentA`");
                Schema("`dbo`");
                CompositeId()
                    .KeyProperty( x => x.M2M2ParentAId1, "`M2M2ParentAId1`" )
                        .KeyProperty( x => x.M2M2ParentAId2, "`M2M2ParentAId2`" );

         HasManyToMany(x => x.M2M2ParentB)
            .Schema("`dbo`")
            .Table("`M2M2Link`")
            .ParentKeyColumn("`M2M2ParentA_Id1`")
            .ParentKeyColumn("`M2M2ParentA_Id2`")
            .ChildKeyColumn("`M2M2ParentB_Id1`")
            .ChildKeyColumn("`M2M2ParentB_Id2`");
            }
        }


        public partial class M2M2ParentBMap : ClassMap<M2M2ParentB>
        {
            public M2M2ParentBMap()
            {
                Table("`M2M2ParentB`");
                Schema("`dbo`");
                CompositeId()
                    .KeyProperty( x => x.M2M2ParentBId1, "`M2M2ParentBId1`" )
                    .KeyProperty( x => x.M2M2ParentBId2, "`M2M2ParentBId2`" );

        HasManyToMany(x => x.M2M2ParentA)
            .Schema("`dbo`")
            .Table("`M2M2Link`")
            .ParentKeyColumn("`M2M2ParentB_Id1`")
            .ParentKeyColumn("`M2M2ParentB_Id2`")
            .ChildKeyColumn("`M2M2ParentA_Id1`")
            .ChildKeyColumn("`M2M2ParentA_Id2`");
            }
        }



        public partial class M2M2LinkMap : ClassMap<M2M2Link>
        {
            public M2M2LinkMap()
            {
                Table("`M2M2Link`");
                Schema("`dbo`");
                CompositeId()
                    .KeyProperty( x => x.M2M2ParentA_Id1, "`M2M2ParentA_Id1`" )
                    .KeyProperty( x => x.M2M2ParentA_Id2, "`M2M2ParentA_Id2`" )
                    .KeyProperty( x => x.M2M2ParentB_Id1, "`M2M2ParentB_Id1`" )
                    .KeyProperty( x => x.M2M2ParentB_Id2, "`M2M2ParentB_Id2`" );

                References(x => x.M2M2ParentA)
                    .Columns("`M2M2ParentA_Id1`","`M2M2ParentA_Id2`").Cascade.All();

                References(x => x.M2M2ParentB)
                    .Columns("`M2M2ParentB_Id1`","`M2M2ParentB_Id2`").Cascade.All();
            }
        }

ERROR:
Foreign key (FKAB0E07EA57E45AB6:M2M2Link [M2M2ParentB_Id2])) must have same number of columns as the referenced primary key (M2M2ParentB [M2M2ParentBId1, M2M2ParentBId2])

DDL

CREATE TABLE [dbo].[M2M2ParentA] ( [M2M2ParentAId1] [int] NOT NULL,
                                   [M2M2ParentAId2] [int] NOT NULL,
CONSTRAINT [PK_M2M2ParentA] PRIMARY KEY CLUSTERED ( [M2M2ParentAId1] ASC, [M2M2ParentAId2] ASC ) )

CREATE TABLE [dbo].[M2M2ParentB] ( [M2M2ParentBId1] [int] NOT NULL,
                                   [M2M2ParentBId2] [int] NOT NULL,
CONSTRAINT [PK_M2M2ParentB] PRIMARY KEY CLUSTERED ( [M2M2ParentBId1] ASC, [M2M2ParentBId2] ASC ) )


CREATE TABLE [dbo].[M2M2Link] ( [M2M2ParentA_Id1] [int] NOT NULL,
                                [M2M2ParentA_Id2] [int] NOT NULL,
                                [M2M2ParentB_Id1] [int] NOT NULL,
                                [M2M2ParentB_Id2] [int] NOT NULL,
CONSTRAINT [PK_M2M2Link] PRIMARY KEY CLUSTERED ( [M2M2ParentA_Id1] ASC, [M2M2ParentA_Id2] ASC, [M2M2ParentB_Id1] ASC, [M2M2ParentB_Id2] ASC ) )



ALTER TABLE [dbo].[M2M2Link]
        WITH CHECK
ADD CONSTRAINT [FK_M2M2Link_M2M2ParentA] FOREIGN KEY ( [M2M2ParentA_Id1], [M2M2ParentA_Id2] ) REFERENCES [dbo].[M2M2ParentA] ( [M2M2ParentAId1],
                                                                                                                               [M2M2ParentAId2] )
ALTER TABLE [dbo].[M2M2Link]
        CHECK CONSTRAINT [FK_M2M2Link_M2M2ParentA]
ALTER TABLE [dbo].[M2M2Link]
        WITH CHECK
ADD CONSTRAINT [FK_M2M2Link_M2M2ParentB] FOREIGN KEY ( [M2M2ParentB_Id1], [M2M2ParentB_Id2] ) REFERENCES [dbo].[M2M2ParentB] ( [M2M2ParentBId1],
                                                                                                                               [M2M2ParentBId2] )
ALTER TABLE [dbo].[M2M2Link]
        CHECK CONSTRAINT [FK_M2M2Link_M2M2ParentB]

Update: I have tried creating a custom key type but was not successful.

Your challenge, if you choose to accept it:

Present code for the best working fluent mapping using this table structure, likely using a custom key type, and the bounty is yours.

Anyone?

解决方案

If FluentNHibernate is currently unable to map this, then you can map it with a hbm.xml file.

I also used a component for the composite id of both classes. This makes the identity separate from the entity, allowing session.Get<M2M2ParentA>( new M2M2Id( 1, 2 )). See this answer for a discussion of the 3 ways to represent composite-id (it is the same for NHibernate and 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>

And my version of your classes.

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

这篇关于流利的NHibernate:如何映射M:N多对多的复合键在两边的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆