Reputation: 1620
I have a class Journal
, which has an IList
of JournalLine
objects.
I created a Journal
and accidentally ran it through the same line generation method twice. The start of this method calls _journalLines.Clear()
and the end does _session.SaveOrUpdate(journal)
. So I have this sequence:
Journal
with no lines, call SaveOrUpdate
. That's fine.JournalLines
with IDs 1,2,3, add to Journal._journalLines
and call SaveOrUpdate
Journal._journalLines.Clear()
. A breakpoint after this shows the lines list to be empty.JournalLines
with IDs 4,5,6, add to Journal._journalLines
and call SaveOrUpdate
. A breakpoint here shows _journalLines
to have three things in it.Journal
that has 6 lines.This all takes place in one transaction and nothing is persisted in the database until it's finished.
Why is this merging the two collections? It seems to me that it should get to the last SaveOrUpdate
where the breakpoint shows it's got three lines, and persist it as having three lines. Are the other three hanging around in memory somewhere because there hasn't been a flush yet?
Edit: Mapping
public JournalMap()
{
// Other stuff
HasMany(x => x.JournalLines)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan();
}
public JournalLineMap()
{
// Other stuff
References(x => x.Journal);
}
Journal
has these:
private readonly IList<JournalLine> _journalLines = new List<JournalLine>();
public virtual IEnumerable<JournalLine> JournalLines
{ get { return _journalLines; } }
The actual code that generates the lines is way too complicated to add here, but it calls _journalLines.Add(journalLine);
after generating them, and then calls this, T being a Journal
public T Add(T entity)
{
_session.SaveOrUpdate(entity);
return entity;
}
Before ultimately calling _session.Flush()
and _session.Transaction.Commit();
if the flush doesn't error.
Upvotes: 2
Views: 860
Reputation: 123861
This issue could be related to the style of Journal mapping. Mostly the cascade setting used for your collection. If you are having cascade setting like save-update or all, e.g.
<bag name="JournalLines" lazy="true" inverse="true" cascade="save-update"
...
Then what is happening (using similar step numbers):
SaveOrUpdate(jurnal)
will do the cascade. It also does the cascading, i.e. session is aware about these 3 items to be persistedClear()
will clear the IList<>
but there is no cascade trigger to remove these items from a session. At this moment, our first 3 JournalLines are really orphans. No one cares about themFlush()
triggered by transaction will isnsert all the JournalLines into DBSolution: change the mapping to
cascade="all-delete-orphan"
NOTE: from definiton you've provided above, I guess that this is the scenario (I just explained)
Other issue you could be, if you call session.SaveOrUpdate(eachJournalLine)
. In that case Clear()
is not enough, you also have to iterate all removed items and set their relation to line.Journal = null
Upvotes: 1