Reputation: 319
My understanding is that when mapping a collection as list and giving a column for indexing then:
Unfortunately, my experience shows that only (1) is working. Here is the mapping:
HasMany(x => x.Attachments)
.AsList( index => index.Column("OrderInProduct") )
.Cascade.AllDeleteOrphan() // Handle cascade upserts
;
Is my expectation for (2) wrong? Is my mapping wrong?
Upvotes: 2
Views: 724
Reputation: 758
You're probably not looking for an answer any longer, but I'll post this here for posterity's sake. There's either a bug in Fluent NHibernate or I'm trying to do something that's disallowed, but when I configured the session factory to export the .HBM.xml file, I found that the HasMany mapping was getting specified as a bag instead of a list, although the sequence number was updated properly. The mapping was responsive to other changes (e.g. .Not.LazyLoad()), but for the life of me I couldn't get it to map as a list.
I ended up putting in a hack, which was partially inspired by this link. In the parent (transcription errors aside :):
private IList<Child> _children;
public virtual IReadOnlyList<Child> Children => _children.OrderBy(la => la.Position).ToList();
protected internal int GetPositionOf(Child child) => _children.ToList().IndexOf(child);
In the child:
private int? _position;
protected internal int Position
{
get
{
var position = _position ?? (_position = Parent.GetPositionOf(this));
return position.HasValue ? position.Value : throw new InvalidOperationException("Child position has no value");
}
set { _position = value; }
}
I continue to map using .AsList so the position gets updated properly:
HasMany(x => x.Children).Access.CamelCaseField(Prefix.Underscore).AsList(x => x.Column(ColumnNames.Position));
In case it helps someone, you can export the .hbm files to see what Fluent Migrator actually generates:
FluentConfiguration configuration = Fluently.Configure()
.Database(dbConfig)
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())
.ExportTo(@"c:\temp\mappings")
Note that you have to have the folder generated in advance or you get an exception.
I'd be interested to hear if anyone else has seen similar behavior; I am using Fluent Migrator 2.1.2 and NHibernate 5.2.7. I've got intentions to submit a bug report, but gotta clear some work off my plate first.
Upvotes: 1
Reputation: 2416
I just played with this, and 2) works for me. Your mapping is OK.
I believe NHibernate orders the collection in memory based on the index column value without issuing "Order By " sql statement. I got the idea that NHibernate could do a memory sorting here - This performs the ordering in the SQL query, not in memory.
I could not find the collection memory sorting in NHibernate code, so to prove the memory sorting works, I removed the primary key (Id, Index) from the child entity table, persisted 2 child entities (index 0, and index 1), manually - using manual sql - switched the index values (so the first record got index 1, and the second record got index 0), then I loaded the parent entity and checked that records were loaded in expected order.
Upvotes: 0
Reputation: 5912
you can add orderby:
HasMany(x => x.Attachments)
.AsList( index => index.Column("OrderInProduct") )
.OrderBy( o => o.Column("OrderInProduct") )
.Cascade.AllDeleteOrphan() // Handle cascade upserts
;
Upvotes: 1