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