1

我正在尝试将对象持久化到数据库中。此操作应涉及两个表。

[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");
    }
}

这是我的映射:

public class EntityMapping<TKey, TEntity> : ClassMapping<TEntity>
    where TEntity : Entity<TKey>
{
    public EntityMapping()
    {
        this.Id(x => x.Id, mapper => mapper.Generator(Generators.GuidComb));
    }
}

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

public class ReportMapping : EntityMapping<Guid, Report>
{
    public ReportMapping()
    {
        this.Table("REPORTS");
        this.Property(x => x.ReportDate, mapper => mapper.Type(NHibernateUtil.Date));
        this.Set(
            x => x.Positions,
            mapper =>
            {
                mapper.Key(km => km.Column("ReportId"));
                mapper.Lazy(CollectionLazy.Lazy);
                mapper.Inverse(true);
                mapper.Cascade(Cascade.All | Cascade.DeleteOrphans);
            },
            rel => rel.OneToMany());
    }
}

这是nhibernate使用的sql:

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '7f4d8f3d-1175-4713-bd1c-a06d00bfc614' /* @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 */,
         '00000000-0000-0000-0000-000000000000' /* @p3_0 */)

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 用于第二个表?

更新:

我试图明确映射 ManyToOne 部分

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 有正确的密钥。有人可以解释这种行为并提供解决方案吗?

4

2 回答 2

2

我很可能会将其映射为复合元素并摆脱整个 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"));
        }));
于 2012-06-11T10:14:38.493 回答
0

经过一番摆弄和攀登 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"));
    }
}

我将 ComposedId 部分声明为 ManyToOne,并从 Position 实体中删除了 Guid 属性。NHibernate 现在根据表 REPORTPOSITIONS 填充 Position 实体中的 Report、Desk 和 Commodity 属性,并将所有 Positions 保存到该表中。

于 2012-06-12T05:59:45.077 回答