我正在尝试将对象持久化到数据库中。此操作应触及两个表。
[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"));
但是有了这个,它甚至都没有尝试插入到reportpositions中;
当我改为做这样的事情时
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有正确的密钥。有人可以解释一下这种行为并提供解决方案吗?
答案 0 :(得分: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"));
}));
答案 1 :(得分: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持久化到此表。