Fluent Mapping Many-Many with sorting

2019-02-27 14:05发布

I'm trying to get a many to many relationship to work using Fluent Nhibernate.

I have a Product and a RelatedProduct Table

Product {Id, Name...}
ProductRelated{Id, ProductId, RelatedProductId, relOrder}

and a Product class

The mapping looks like

  HasManyToMany(x => x.RelatedProducts)
                .Table("ProductRelated")
                .ReadOnly()
                .ChildOrderBy("relOrder asc")
                .ParentKeyColumn("ProductId")
                .ChildKeyColumn("RelatedProductId");

When a query is done for Product and the RelatedProducts are lazy loaded I can see that the sorting is applied correctly using the relOrder on the join table.

Session.Query<Product>()
       .FetchMany(p => p.Categories)
       .FetchMany(p => p.Departments)

Once I add in eager loading of the related products NHibernate tries to sort by a relOrder column on the product itself instead of on the join table.

Session.Query<Product>()
       .FetchMany(p => p.Categories)
       .FetchMany(p => p.Departments)
       .FetchMany(p => p.RelatedProducts)

Any ideas of whats going on here?

1条回答
对你真心纯属浪费
2楼-- · 2019-02-27 14:31

Well to answer your question what's going on here?, I would say, you are using: "not-together fitting features" of NHibernate.

A snippet from documentation 6.6. Sorted Collections:

Setting the order-by attribute tells NHibernate ...

Note: that lookup operations on these collections are very slow if they contain more than a few elements.

Note: that the value of the order-by attribute is an SQL ordering, not a HQL ordering!

So, this could be applied only for "standard" lazy loading, becuase this kind of a feature is applied only on a DB side. It is not managing order in the memory.

And the eager fetching, as the counter-part, is a different way how to generate and issue the SQL Statement to DB.

So, eager and order-by will never work together.

*

My NOTE: I simply have to append this. I can't help myself

I.

The Eager fetching is the feature which should be avoided (I never use it, but it's me). There is a better solution and it is setting the BatchSize(), which will reduce the 1+N into 1+(a few) and will keep all the (lazy) featrues, including order-by. Check these if interested:

BatchSize() is supported for HasManyToMany as well: ToManyBase:

/// <summary>Specify the select batch size </summary>
/// <param name="size">Batch size</param>
public T BatchSize(int size) { ...

II.

The many-to-many mapping, while fancy at first look, is not the way I'd suggest. Try to rethink your model and introduce the first-level-citizen: PairingEntity - for the pairing object. It will then use many-to-one and one-to-many mapping which could give us more... e.g. improved querying like Subqueries... try to check these:

查看更多
登录 后发表回答