在NHibernate 3.2中插入子表时,如何使用生成的Guid主键作为外键?

在NHibernate 3.2中插入子表时,如何使用生成的Guid主键作为外键?,nhibernate,insert,foreign-keys,nhibernate-mapping,primary-key,Nhibernate,Insert,Foreign Keys,Nhibernate Mapping,Primary Key,我正在尝试将一个对象持久化到数据库中。此操作应接触两张桌子 [HttpPost] public ActionResult Create(Report report) { try { report.Positions = new Iesi.Collections.Generic.HashedSet<Position>(); var desks = this.session.Query<Desk>().ToList();

我正在尝试将一个对象持久化到数据库中。此操作应接触两张桌子

[HttpPost]
public ActionResult Create(Report report)
{
    try
    {
        report.Positions = new Iesi.Collections.Generic.HashedSet<Position>();
        var desks = this.session.Query<Desk>().ToList();

        foreach (var desk in desks)
        {
            foreach (var comm in desk.Commodities)
            {
                report.Positions.Add(
                    new Position
                        {
                            Report = report,
                            ReportId = report.Id,
                            Desk = desk,
                            DeskId = desk.Id,
                            Commodity = comm,
                            CommodityId = comm.Id,
                            Value = .0
                        });
            }
        }

        this.session.Save(report);
        return this.RedirectToAction("Index");
    }
    catch
    {
        // some handling
        return this.RedirectToAction("Index");
    }
}
sql语句中的ReportId是C#的默认值(GUID),因为我没有在控制器操作中设置它。NHibernate生成报表表的id。当我在控制器操作中设置Id时

report.Id = Guid.NewGuid();
sql使用不同的ID作为参数:

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '6164264e-29cd-4d9c-befd-a06d00c2defd' /* @p1_0 */)

INSERT INTO REPORTPOSITIONS
        (Position,
         CommodityId,
         DeskId,
         ReportId)
VALUES  (0 /* @p0_0 */,
         '3a7d80c4-85e9-ba4b-80d2-064f7f0b58b5' /* @p1_0 */,
         'ed7c4e75-7417-a241-a40a-0ff4bfad7172' /* @p2_0 */,
         '594b2206-7c25-4430-af18-5f2643f6c7bf' /* @p3_0 */)
如何使用NHibernate为第二个表生成的id

更新:

我试图明确地映射出多个部分

this.ManyToOne(x => x.Report, mapper => mapper.Column("ReportId"));
但有了这一点,它甚至不尝试插入报告位置

当我做这样的事情时

this.ManyToOne(x => x.Report, mapper => mapper.Column("foo"));
它创建这个sql语句

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '4ff74d49-8749-400c-b079-a06d00e0bee5' /* @p1_0 */)

INSERT INTO REPORTPOSITIONS
        (foo,
         Position,
         CommodityId,
         DeskId,
         ReportId)
VALUES  ('4ff74d49-8749-400c-b079-a06d00e0bee5' /* @p0_0 */,
         0 /* @p1_0 */,
         '3a7d80c4-85e9-ba4b-80d2-064f7f0b58b5' /* @p2_0 */,
         'ed7c4e75-7417-a241-a40a-0ff4bfad7172' /* @p3_0 */,
         '00000000-0000-0000-0000-000000000000' /* @p4_0 */)

现在foo有了正确的密钥。有人能解释一下这个行为并提供一个解决方案吗?

我很可能会将它映射为一个复合元素,并消除整个id问题。如果要对其进行检查,可以创建唯一约束

this.Set(
        x => x.Positions,
        mapper =>
        {
            mapper.Key(km => km.Column(c => 
            {
              c.Name("ReportId");
              c.UniqueKey("ReportDeskCommodity");
            }));
            mapper.Lazy(CollectionLazy.Lazy);
        },
        rel => rel.Component(comp => 
        {
            comp.Parent(p => p.Report);

            comp.Property(
              p => p.DeskId, 
              m => m.Column(c => c.UniqueKey("ReportDeskCommodity")));

            comp.Property(
              p => p.CommodityId, 
              m => m.Column(c => c.UniqueKey("ReportDeskCommodity")));

            comp.Property(
              x => x.Value, 
              m => m.Column("Position"));
        }));
如果没有很好的理由映射关键点,实际上可以将其设置为多对一。这是对域模型的更改

        rel => rel.Component(comp => 
        {
            comp.Parent(p => p.Report);

            comp.ManyToOne(
              p => p.Desk, 
              m => m.Column(c => 
              {
                c.Name("DeskId");
                c.UniqueKey("ReportDeskCommodity");
              }));


            comp.ManyToOne(
              p => p.Commodity, 
              m => m.Column(c => 
              {
                c.Name("CommodityId");
                c.UniqueKey("ReportDeskCommodity");
              }));

            comp.Property(
              x => x.Value, 
              m => m.Column("Position"));
        }));

经过一番磨蹭和攀爬NHibernates陡峭的学习曲线后,我想出了这个解决方案

public class PositionMapping : ClassMapping<Position>
{
    public PositionMapping()
    {
        this.Table("REPORTPOSITIONS");
        this.ComposedId(
            x =>
            {
                x.ManyToOne(p => p.Report, mapper => mapper.Column("ReportId"));
                x.ManyToOne(p => p.Desk, mapper => mapper.Column("DeskId"));
                x.ManyToOne(p => p.Commodity, mapper => mapper.Column("CommodityId"));
            });
        this.Version(x => x.Version, mapper => mapper.Generated(VersionGeneration.Always));
        this.Property(x => x.Value, mapper => mapper.Column("Position"));
    }
}
公共类位置映射:类映射
{
公共位置映射()
{
本表(“报告头寸”);
这个人沉着冷静(
x=>
{
x、 manytone(p=>p.Report,mapper=>mapper.Column(“ReportId”);
x、 manytone(p=>p.Desk,mapper=>mapper.Column(“DeskId”));
x、 manytone(p=>p.Commodity,mapper=>mapper.Column(“CommodityId”);
});
this.Version(x=>x.Version,mapper=>mapper.Generated(VersionGeneration.Always));
属性(x=>x.Value,mapper=>mapper.Column(“位置”);
}
}

我将ComposedId部分声明为manytone,并从Position实体中删除Guid属性。NHibernate现在根据表REPORTPOSITIONS填充Position实体中的报表、桌面和商品属性,并将所有位置分配到此表。

我尝试了这种方法,它首先抱怨列“ReportId”(1.
mapper.Key(km=>km.column(“ReportId”);
2.
comp.Property)的多重映射(p=>p.ReportId);
删除第二个映射后,它只插入到报表表中。我无法识别反向引用。您需要将其映射为
Parent
。该属性是对报表的引用,而不是id。它不能是反向的,因为它不是反向的。这就是它不存储任何内容的原因(相反的意思是内存中有另一个引用包含相同的信息,因此不需要存储。)使用代码删除父设置(它引发了MappingException)会使两个表中的插入都起作用。但是当我现在使用
session.Get(1)时
集合中的Position对象不包含/获取desk和commodity对象。您知道如何解决这个问题吗?如果您在存储之前正确添加了它们,并且给定的映射正是您所拥有的(没有其他DeskId属性和顶部代码中的内容),它应该可以工作。顺便说一句,我修复了唯一键并为外键添加了列名。使用更新的this.Set和组件映射,我仍然得到一个MappingException
无法确定以下列的类型:Report,MyProject,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null,columns:NHibernate.mapping.column(Report)
因为这一行
公司母公司(p=>p.Report);
但如果没有此选项,当我尝试从数据库中读取报告时,Positions集合将保持为空。我可以添加一个新的集合,它将正确插入所有行,但之后无法提取->
无法重新关联未初始化的临时集合
您应该避免使用复合ID。此功能用于遗留数据库有趣的是,在NHibernate中不鼓励使用composeId吗?在我的示例中,这样使用它对我来说是有意义的,而且它是有效的。
        rel => rel.Component(comp => 
        {
            comp.Parent(p => p.Report);

            comp.ManyToOne(
              p => p.Desk, 
              m => m.Column(c => 
              {
                c.Name("DeskId");
                c.UniqueKey("ReportDeskCommodity");
              }));


            comp.ManyToOne(
              p => p.Commodity, 
              m => m.Column(c => 
              {
                c.Name("CommodityId");
                c.UniqueKey("ReportDeskCommodity");
              }));

            comp.Property(
              x => x.Value, 
              m => m.Column("Position"));
        }));
public class PositionMapping : ClassMapping<Position>
{
    public PositionMapping()
    {
        this.Table("REPORTPOSITIONS");
        this.ComposedId(
            x =>
            {
                x.ManyToOne(p => p.Report, mapper => mapper.Column("ReportId"));
                x.ManyToOne(p => p.Desk, mapper => mapper.Column("DeskId"));
                x.ManyToOne(p => p.Commodity, mapper => mapper.Column("CommodityId"));
            });
        this.Version(x => x.Version, mapper => mapper.Generated(VersionGeneration.Always));
        this.Property(x => x.Value, mapper => mapper.Column("Position"));
    }
}