Reputation: 4157
I have the following mapping classes (only the relevant part copied):
public class CardTemplateMapping : ClassMap<CardTemplate>
{
public CardTemplateMapping()
{
Table("cardtemplate");
Id(x => x.Id)
.Column("id")
.GeneratedBy.Native();
HasMany(x => x.CostStructures)
.KeyColumn("cardtemplate_id")
.Cascade.All();
}
}
public class CostStructureMapping : ClassMap<CostStructure>
{
public CostStructureMapping()
{
Table("coststructure");
Id(x => x.Id)
.Column("id")
.GeneratedBy.Native();
References(x => x.CardTemplate)
.Column("cardtemplate_id");
HasMany(x => x.CostComponents)
.KeyColumn("coststructure_id")
.Cascade.AllDeleteOrphan();
}
}
public class CostStructureComponentMapping : ClassMap<CostStructureComponent>
{
public CostStructureComponentMapping()
{
Table("CostStructureComponent");
Id(x => x.Id)
.Column("id")
.GeneratedBy.Native();
References(x => x.CostStructure)
.Column("coststructure_id");
References(x => x.ResourceType)
.Column("resourcetype_id");
}
}
Nhibernate loads the relations as I intended. But two parts of the Mapping seem a bit weird (either that or my expectations are weird).
First:
CostStructure structure = new CostStructure() { CardTemplate = template };
template.CostStructures.Add(structure);
Session.Save(template);
Session.Flush();
This does not save the new CostStructure
instance. Why?
Second one: Assuming I have loaded a CardTemplate
having a CostStructure
containing three CostStructureComponent
entities. Now I want to remove one of those CostStructureComponents
from the CostStructure
.
I tried the following :
costStructure.CostComponents.Remove(component);
component.CostStructure = null;
session.Save(template)
Now, I know that explicitly deleting explicitly works, but shouldn't the DeleteOrphan
part also assert that the component, now without CostStructure
to reference, is deleted? Instead, NHibernate tries to perform the following update:
UPDATE CostStructureComponent
SET amount = @p0,
coststructure_id = @p1,
resourcetype_id = @p2
WHERE id = @p3;
@p0 = 1 [Type: Int32 (0)],
@p1 = NULL [Type: Int64 (0)],
@p2 = 5 [Type: Int64 (0)],
@p3 = 13 [Type: Int64 (0)]
Could it be Equals / GetHashCode have been implemented the wrong way?
Sorry, it's late, been a long day and so forth...If I'm talking gibberish, please let me know...
Upvotes: 1
Views: 1173
Reputation: 123861
All the answers are hidden in one setting .Inverse()
public CardTemplateMapping()
{
HasMany(x => x.CostStructures)
.KeyColumn("cardtemplate_id")
.Cascade.All()
.Inverse(); // HERE this setting
And here:
public CostStructureMapping()
{
..
HasMany(x => x.CostComponents)
.KeyColumn("coststructure_id")
.Cascade.AllDeleteOrphan()
.Inverse(); // and HERE and everywhere on HasMany()
Try to find some articles about this setting, but in general: If mapped as inverse, NHibernate is ready to do much better SQL Statements, because it is working with other end of relation...
Some sources:
19.5.2. Lists, maps, idbags and sets are the most efficient collections to update cite:
However, in well-designed NHibernate domain models, we usually see that most collections are in fact
one-to-many
(comment: HasMany in Fluent) associations withinverse="true"
. For these associations, the update is handled by themany-to-one
(comment: References in Fluent) end of the association, and so considerations of collection update performance simply do not apply.
inverse (optional - defaults to false) mark this collection as the "inverse" end of a bidirectional association
Upvotes: 1