代码之家  ›  专栏  ›  技术社区  ›  Sky Sanders

fluent nhibernate:如何将m:n多对多映射为两边都有复合键

  •  1
  • Sky Sanders  · 技术社区  · 15 年前

    好吧,问题就在这里。它甚至不像一个想要在他的pks中用不同的列计数映射m:n的人那样疯狂。

    无论我做什么或在哪里查看,似乎没有任何方法链能够成功映射这一点。

    我试过在父列和子列上加倍,例如parentcolumn(“”)、parentcolumn(“”)、childcolumn(“”)、childcolumn(“”)-认为这样做不起作用,我是对的。

    尝试使用foreignkeyconstraintname,但没有运气。不过,fnh正在将一侧映射到单个键。

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

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

    敌我识别

    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]
    

    更新: 我尝试创建自定义密钥类型,但没有成功。

    如果你选择接受挑战:

    提供最佳代码 工作 使用这个表结构进行流畅的映射,可能使用自定义键类型,并且边界是您的。

    有人吗?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Community CDub    8 年前

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

    我还为两个类的复合ID使用了一个组件。这使得标识与实体分离,允许 session.Get<M2M2ParentA>( new M2M2Id( 1, 2 )) .参见 this answer 讨论三种表示复合ID的方法(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;
        }
    }
    
        2
  •  1
  •   Danno    15 年前

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

    长话短说的是,如果两个父表的组合键不是由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时使用.exportto(“c:\”)函数,您只需编辑Fluent输出的hbm文件即可。这是一个很好的起点。

    HTH -丹诺