nHibernate QueryOver performing a SubSelect to load a collection instead of a Join - nhibernate

Ok I'm trying to load some many to many collections on my User object (Followers, Following, PostLikes, CommentLikes). However when I perform a Left Join on these collections using QueryOver it returns more records than should be returned.
I looked at the SQL with SQL Profiler and it seems as instead of just producing 4 joins it is producing 8 creating a somewhat looping query. This is my current query.
User userAlias = null;
User followingAlias = null;
User followersAlias = null;
Post postLikesAlias = null;
Comment commentLikesAlias = null;
var entity = Session.QueryOver(() => userAlias)
.Where(x => x.Id == id)
.Left.JoinAlias(() => userAlias.Followers, () => followersAlias)
.Left.JoinAlias(() => userAlias.Following, () => followingAlias)
.Left.JoinAlias(() => userAlias.PostLikes, () => postLikesAlias)
.Left.JoinAlias(() => userAlias.CommentLikes, () => commentLikesAlias)
.SingleOrDefault();
ReleaseCurrentSession();
return entity;
Anyway when I do not selectively load things and use eager loading through my fluent mappings. The collections load perfectly. Again I looked at Sql Profiler and it seems to execute a separate select query for each collection. Is there a way I can do this using QueryOver instead of using joins? I know in your mappings you can specify FetchTypes, but when I do this and just use .Fetch(x => x.Followers) etc it still produces a join!
Thanks in advanced,
Jon

Try using this as the end of your query.
.TransformUsing(new DistinctRootEntityResultTransformer())
.SingleOrDefault();
or
.TransformUsing(new DistinctRootEntityResultTransformer())
.List();
and accessing the first item.

You can't do it that way. NHibernate doesn't issue separate queries for collections. So querying a collection is easy when you're only dealing with a single collection off the root.
You can use CreateMultiCriteria() to create separate queries batched together and transform them into a single result.
Alternatively i believe you can also use .Future() on each of the queries so they are batched together, NH will use first level cache to grab the collections.

Related

NHibernate - why is this collection not initialized / eager fetched?

Considering this:
var pfs = Session.QueryOver<Pegfile>()
.JoinAlias(pf => pf.Responses, () => responseAlias)
.List();
followed by this
Debug.Print(pfs.First().Responses.Count.ToString());
Why would that debug statment make NHibernate go back and requery the Response collection, surely it was initialized in the first query?
You need to use Fetch to pre-load the collection:
var pfs = Session.QueryOver<Pegfile>()
.JoinAlias(pf => pf.Responses, () => responseAlias)
.Fetch(pf => pf.Responses).Eager
.List();
JoinAlias aliases the collection so that you can reference it in a where clause, etc.
I'm not sure about QueryOver but the LINQ provider also uses several optimizations that would cause the collection to not be loaded, such as issuing a SQL aggregate COUNT query when you invoke Count.
Gets me every single time, why don't i remember? The join has to be a Lefty - grr love and hate NH in equal measures.
var pfs = Session.QueryOver<Pegfile>()
.Left.JoinAlias(pf => pf.Responses, () => responseAlias)
.List();

queryover and is in a list filter

I dont really understand how I can perform this query using nhibernate queryover, I currently have:
var users= _session.QueryOver<User>().Future();
var comps = _session.QueryOver<UserCompetency>()
.Where(x => users.Any(match => x.UserID == match.UserID)).Future();
an exception keeps getting thrown, using linq to sql this works perfectly fine?
QueryOver is not LINQ. It does not support arbitrary expressions.
Use the Query extension method if that's what you need.

How to join using NHibernate QueryOver

I have the following situation in my code and am not able to solve it. Situation -
var grpA = Session.QueryOver(() => _employeeGroupRelation));
var grpB = Session.QueryOver(() => _employeeGroup));
// var grpC should join grpA and grpB on _employeeGroupRelation.groupID = _employeeGroup.ID
Question -
Is there some way to join grpA and grpB using QueryOver syntax?
Is it possible to do this without using the List() on grpA or grpB, because each of them will hold close to 10,000 records and I don't want to dump them into memory.
Is this the right use of QueryOver? Are there cleaner ways of achieving what I'm trying to solve?
It maybe a basic doubt, but I'm a newbie to NHib and QueryOver.
Edit -
select * from employeeGroup a
inner join employeeGroupRelation b on a.ID = b.ID
This is what I'm trying to do in SQL.
The easiest way to do it:
session.QueryOver<EmployeeGroup>()
.JoinQueryOver(employeeGroup => employeeGroup.EmployeeGroupRelation)
.Take(1000) // The same as top in SQL, if you don't want load all of entities
.TransformUsing(Transformers.DistinctRootEntity)
.List();
"JoinQueryOver" gets "EmployeeGroup" and related "EmployeeGroupRelation" as proxy (depends from mapping) for LazyLoad
If you don't want to use LazyLoad, you can do this:
session.QueryOver<EmployeeGroup>()
.Fetch(employeeGroup => employeeGroup.EmployeeGroupRelation).Eager
.Take(1000) // The same as top in SQL, if you don't want load all of entities
.TransformUsing(Transformers.DistinctRootEntity)
.List();
"Fetch" gets "EmployeeGroup" and related "EmployeeGroupRelation" (not proxy)

NHibernate Queryover - How do I return only a child collection

I am running into difficulty with the following nhibernate queryover query. I am probably over-complicating things, but here is the problem:
I have an entity named AuctionStatistic that links to an auction (this is uni-directional and I do not have links from auctions back to statistics)
I would like to query the statistic table, find all auction IDs and pull back only those that meet a certain threshold - i.e. top 500 auctions by views
Once I've gotten the top X (in this example i'm hardcoding to 10000 views) I want to pull back the auction id and name. For this particular query I don't need any of the data stored in the statistics table (though this is used elsewhere and is not redundant)
I figured I could use something like the following to get back just the auctions, but because I'm querying over AuctionStatistic it expects the selected value to be of type AuctionStatistic (or a list thereof)
var auctions = _session.QueryOver<AuctionStatistic>().Where(c => c.ViewCount > 10000).Fetch(x=>x.Auction).Eager.Select(x=>x.Auction);
Can anyone suggest a better way of doing this?
Thanks
JP
Without bi-directional this is probably your best bet.
Auction auctionAlias = null;
AuctionDTO dto = null;
var auctionDtos = _session.QueryOver<AuctionStatistic>()
.Where(c => c.ViewCount > 10000)
.JoinAlias(x => x.Auction, () => auctionAlias)
.SelectList(list => list
.Select(() => auctionAlias.id).WithAlias(() => dto.id)
.Select(() => auctionAlias.name).WithAlias(() => dto.name))
.TransformUsing(Transformers.AliasToBean<AuctionDTO>())
.List<AuctionDTO>();

Am I doing something wrong with Nhibernate Query Over fetch?

I have this
using (ITransaction transaction = session.BeginTransaction())
{
Task tAlias = null;
CompletedTask cAlias = null;
List<Task> tasks = session.QueryOver<Task>(() => tAlias)
.Where(Restrictions.In(Projections.Property(() => tAlias.Course.Id), courseIds))
.Fetch(pt => pt.PersonalTaskReminders).Eager
.List<Task>().ToList().ConvertToLocalTime(student);
transaction.Commit();
return tasks;
}
PersonalTaskReminders == Collection
So a task can have many personalTaskReminders. I am finding though if I set 2 personalTaskReminders(so PersonalTaskReminders will now have 2 rows in it's collection from the db)
That it returns the same task twice.
So if I had 50 personaltaskReminders for that task. I would get 50 results of the same task. I don't understand why.
If I remove the eager loading. I get the one task back from the database as I expected.
It is obvious, because eager fetch causes join with 2 tables. To get rid of duplicated results you should use DistinctRootEntityTransformer.
By the way, NHibernate offers much nicer syntax for IN clause. So your query should look like this:
var tasks = Session.QueryOver<Task>()
.WhereRestrictionOn(x => x.Id).IsIn(courseIds)
.Fetch(pt => pt.PersonalTaskReminders).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.List<Task>();
Xelibrion's solution is the right way to fix the problem.
To understand why the results are duplicated when doing Fetch, you can compare the generated SQL:
Without Fetch the fields in the SELECT are just your root entity Task fields.
With Fetch the fields of PersonalReminder entities have been added to the SELECT. So if you have two PersonalReminder registers for the same Task you get two registers in the results, and a DISTINCT clause would not remove them (as the real returned registers are different because they contain the PersonalReminder fields).
The SQL generated with and without TransformUsing is exactly the same, but NH processes the returned registers to remove the duplicates.