Been looking around for a way to do an eager loading join of entities from different SQL Databases but in the same physical server.
For related Entities (or tables), using Fetchmany will Eager Load the parent and Related Entity
var list = DummyRepository.Queryable()
.FetchMany(nav => nav.RelatedEntity1)
.ToList();
Now, for unrelated entities, is doing a (Lambda/ LINQ) .Join the only way these 2 unrelated entities?
I think is not posible use Query or QueryOver APIs with unmapped classes.
I recommend to use session.CreateSQLQuery or session.GetNamedQuery to call or create your queries in SQL and then use DTOs loaded by AliasToBeanTransformer like here.
Or using query.AddEntity to load the result in your domain entities like here.
Related
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?
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:
NHibernate QueryOver with Fetch resulting multiple sql queries and db hits
Is this the right way to eager load child collections in NHibernate
https://stackoverflow.com/questions/18419988/
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:
How to create NHibernate HasManyToMany relation
many-to-many with extra columns nhibernate
Nhibernate: How to represent Many-To-Many relationships with One-to-Many relationships?
I'm a beginner in NHibernate. I have to write a complex query on say an "Employee" to populate all the associations for Employee based on the where clause. What I'm looking for is similar to this - when you do a Employee.FindById(10) should fill up OwnedDepartment, SubscribedGroups etc.
The Employee model I need to populate is really heavy (many associations with other objects)
but I need to populate only few associations. How do I achieve it using a query over? or any other approaches?
Updated
I was reading about eager loading just now, has it something to do with the loading ? In my map I have not mentioned any loading techniques, so by default all of my employee's child element are getting loaded already. There is a bunch of queries getting triggered underneath.
All the associations are lazy loaded by default. That means that the load is triggered when you access it - that's why so many queries are issued. If you want to eagerly load the data (which means either joining the tables or - rarely - doing additional select queries at once), you have to specify it in your mapping or query, depending how you fetch your data. The concept is generally called "eager fetching".
If you want to get a single Employee by ID, the standard way to do it is using session.Get<Employee>(10) - but that approach means that eager loads need to be specified in the mapping. For mapping by code it will be c.Lazy(CollectionLazy.NoLazy); for collections or c.Lazy(LazyRelation.NoProxy) for many-to-one - see here or here for details.
I prefer specifying that kind of things in the query - just where it is used, not globally for the whole entity, regardless who is fetching and what for. In LINQ provider you have FetchMany(x => x.SubscribedGroups) for collections and Fetch(x => x.OwnedDepartment) for many-to-one relations. You can find similiar options in QueryOver, if that's your choice.
I have 2 tables ATable and AATable where both have a shared Primary Key - ATable.aKey and AATable.aKey to represent a one-to-one relationship. For my Fluent mapping I have a HasOne Relationship defined within my Fluent ATableMapping, all of which works fine. However I have noticed that querying for ATable generates a 2nd query (N+1) for the child Table AATable. My understanding is that Hasone eager loads by default, and I had assumed this would be part of the query for ATable, but I may well have this wrong?
I have researched various solutions including using .Not.LazyLoad().Fetch.Join(), PropertyRef, ForeignKey but I cannot seem to resolve the n+1 so that either it is Eager loaded with 1 query, or Lazy loaded and I can fetch the child with my queries.
Has anyone had any issues with this or have an example they know to work with no n+1? Grateful for any advice.
You have two options:
Not.LazyLoad() which disables possibility to provide lazy loaded related entity and it would enforce NHB to provide corresponding subselect within original query
Use component mapping so both entities point to the same table. This is better approach as once you decided to fetch both entities together, generated queries hit only one table - not two like within first option. This is definitely better for performance.
i am trying to turn off lazyloading for one-to-many mapping in NHibernate. I have the follow mapping in my entity mapping class. An entity has many addresses, and what I was looking for is one query that basically join the base table to the Addresses table and return me all the result in one request. Instead I see a series of sql query submitted to database for each record in the base table.
HasMany(m => m.Addresses).Not.LazyLoad().Fetch.Join();
i need a way to turn off lazyloading completely.
I would strongly suggest to read this blog post by Ayende: NHibernate is lazy, just live with it.
Using ORM and trying to avoid laziness... won't work. In case of addresses you will lose paging for example.
(while fetching them via join, what happens? If there will be entity with 10
addresses, and you will ask for first 10 records... you will get just
one. And it could be worse if you will ask for 11...)
But what you can use, is the power of NHibernate: 19.1.5. Using batch fetching
HasMany(m => m.Address)
...
.Fetch.Select()
.BatchSize(25)
Now, if you will need 25 records, there will be 2 SELECTs. First for entity, second for all the related Addresses. That's improvement, while all the advantages of ORM remain.
I think that would be anough:
HasMany(m => m.Addresses).Not.LazyLoad();
To get the data with select you should explicitly use "Fetch":
session.QueryOver<Item>()
.Fetch(item => item.Addresses).Eager
.Take(1000)
.TransformUsing(Transformers.DistinctRootEntity)
.List();
I assume you load the base entity with a HQL, Linq or plain SQL query. Those queries ignore the "join" fetch settings in the mapping. You have to either explicitly fetch the Adresses in the query or use Get/Criteria/QueryOver.
Reference documentation: http://nhibernate.info/doc/nh/en/index.html#performance-fetching-custom
Is there a way of dynamically setting the loading strategy between two entities at load time?
For example if I have a Parent entity that has a list of Child entities, I may want to load the 'Parent' entity with lazy loaded children in some situations and eager loading in others.
Is there a way to do this? The mapping seems to imply its one or the other.
Yes the suggested strategy is to default your entities to use lazy loading, and then when you want to eager load them you change your Query and specify that you want your children to be loaded eagerly.
As to how you actually implement the eager loading, it depends on what query style you're using. (i.e. Linq2NH, Criteria, HQL)
For example, with Linq2NH I believe it's something like this:
session.Query<Parent>().Fetch(p => p.Child)...
With HQL you would use
fetch
Like this:
from Parent as p left join fetch p.Child...
and finally, with the Criteria API, you would do something like this:
var criteria = context.Session.CreateCriteria<Parent>();
criteria.SetFetchMode("Child", NHibernate.FetchMode.Eager);
....