I am trying to persist an object into the database. This operation should touch two tables.
[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");
}
}
This is my mapping:
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());
}
}
and this is the sql used by nhibernate:
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 */)
The ReportId in the sql statement is C#’s default(GUID), because i have not set it in the controller action. NHibernate generates the id for the reports table. When I set the Id in the controller action
report.Id = Guid.NewGuid();
the sql uses different ids as parameters:
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 */)
How do I use the id generated by NHibernate for the second table?
UPDATE:
I tried to map the ManyToOne part explicitly
this.ManyToOne(x => x.Report, mapper => mapper.Column("ReportId"));
but with this it does not even try to insert into reportpositions;
When I instead do something like this
this.ManyToOne(x => x.Report, mapper => mapper.Column("foo"));
it creates this sql statement
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 */)
now foo has the correct key. Could someone please explain this behavior and offer a solution?
After some fiddling around and climbing NHibernates steep learning curve I came up with this solution.
I declared the ComposedId parts as ManyToOne and removed the Guid properties from the Position entity. NHibernate now populates the Report, Desk and Commodity properties in the Position entity according to table REPORTPOSITIONS and also persits all Positions to this table.