FluentHibernate:将复合主键映射到多个级别

时间:2011-11-10 08:20:48

标签: hibernate fluent-nhibernate nhibernate-mapping

我有三张桌子: BillHead,BillDet,BilDetDet,带有以下数据库图 DB Diagram

PK和FK的定义如下:

Table Name     Primary Key                    Foreign Key          FK Table
--------------------------------------------------------------------------------
BillHead         BillNo                            -                  -
BillDet         BillNo, SerialNo                BillNo              BillHead  
BilDetDet    BillNo, SerialNo, DetialSeqNo   BillNo, SerialNo       BillDet   

我已完成映射和伪代码如下:

//BillHeadMap

public class BillHeadMap : ClassMap<BillHead>
{
    public BillHeadMap()
    {
        Table("BillHead");
        LazyLoad();
        Id(x => x.BillNo).GeneratedBy.Identity().Column("BillNo");
        Map(x => x.CustName).Column("CustName").Not.Nullable().Length(50);
        Map(x => x.BillAmt).Column("BillAmt").Not.Nullable();
        HasMany(x => x.BillDets).KeyColumn("BillNo").Cascade.All().Inverse();
    }
}

//BillDetMap
public class BillDetMap : ClassMap<BillDet>
{
    public BillDetMap()
    {
        Table("BillDet");
        LazyLoad();
        CompositeId()
            .KeyReference(x => x.BillHead, "BillNo")
            .KeyProperty(x => x.SerialNo, "SerialNo");
        Map(x => x.ItemName).Column("ItemName").Not.Nullable().Length(20);
        Map(x => x.ItemAmt).Column("ItemAmt").Not.Nullable();
        HasMany(x => x.BilDetDets).KeyColumns.Add("BillNo", "SerialNo").Cascade.All().Inverse().Table("BilDetDet");
    }
}

//BilDetDetMap
public class BilDetDetMap : ClassMap<BilDetDet>
{
    public BilDetDetMap()
    {
        Table("BilDetDet");
        LazyLoad();
        CompositeId()
            .KeyProperty(x => x.BillNo, "BillNo")
            .KeyProperty(x => x.SerialNo, "SerialNo")
            .KeyProperty(x => x.DetailSeqNo, "DetailSeqNo");
        Map(x => x.DetailAmt).Column("DetailAmt").Not.Nullable();
    }
}  

当我尝试使用以下代码保存帐单时:

using (var sqlTrans = session.BeginTransaction()) {
    BillHead bh = new BillHead() { CustName = "Rama", BillAmt = 50000.00M };
    BillDet bd = new BillDet() { SerialNo = 101, ItemName = "BG", ItemAmt = 50000.00M };
    BilDetDet dd1 = new BilDetDet() { DetailSeqNo = 1001, DetailAmt = 20000.00M };
    BilDetDet dd2 = new BilDetDet() { DetailSeqNo = 1002, DetailAmt = 30000.00M };

    AddFirstLevelBillBetails(bd, dd1, dd2);
    AddSecondBillDetailBill(bh, bd);

    session.Save(bh);
    sqlTrans.Commit();
}


private void AddSecondBillDetailBill(BillHead bh, params BillDet[] bds)
{
    foreach (BillDet bd in bds) {
        bh.AddNewBillDetail(bd);
        bd.BillHead = bh;
    }
}

private void AddFirstLevelBillBetails(BillDet bd, params BilDetDet [] bdds)
{
    foreach (BilDetDet bdd in bdds) {
        bd.AddBillDetail(bdd);
        bdd.BillDet = bd;
    }
}

我在sqlTrans.Commit()语句中收到以下错误。

  

无法插入:   [Sample.CustomerService.Domain.BilDetDet#Sample.CustomerService.Domain.BilDetDet] [SQL:   INSERT INTO BilDetDet(DetailAmt,BillNo,SerialNo,DetailSeqNo)   价值观(?,?,?,?)]

我使用sql server profiler对此进行了分析,我发现正在为BillHead和BillDet表构建正确的insert语句。对于BilDetDet表,BillNo和SerialNo列未分配任何值(它们仅为零)。我附上了探查者文字:

exec sp_executesql N'INSERT INTO BilDetDet (DetailAmt, BillNo, SerialNo, DetailSeqNo) VALUES (@p0, @p1, @p2, @p3)',N'@p0 decimal(28,5),@p1 int,@p2 int,@p3 
int',@p0=100.21000,@p1=0,@p2=0,@p3=101

请注意,BillNo和SerialNo列分配为零,因此sql失败。

请更正映射。提前谢谢。

1 个答案:

答案 0 :(得分:2)

不应该是:

public BilDetDetMap()
{
    CompositeId()
        .KeyReference(x => x.BillDet, "BillNo", "SerialNo")
        .KeyProperty(x => x.DetailSeqNo, "DetailSeqNo");
}

更新:我的信息来源

  • 智能感知
  • mapping compositeKeys
  • 使用以下代码将代码粘贴到控制台应用程序中

    var config = Fluently.Configure()
        .Database(SQLiteConfiguration.Standard.InMemory().ShowSql().FormatSql())
        .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())
        )
        .BuildConfiguration();
    
        var sf = config.BuildSessionFactory();
    
        using (var session = sf.OpenSession())
        {
            new SchemaExport(config).Execute(true, true, false, session.Connection, null);
    
            // copy in test code here
        }
    

:d