NHibernate Queryover - How do I return only a child collection - nhibernate

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>();

Related

Narrowing query to use as a source for SelectList in MVC3 with Entity Framework

I have some big entities with about 20 properties, and in some cases I need to create DropDownLists from that. In a SelectList you only end using 2 properties (ID and Name) from the original 20 returned by the query.
I'm using this method to load this:
new SelectList(db.Contacts.AsNoTracking().Where(x => x.idTenant == CurrentTenantID), "ContactId", "Name");
This is working fine, but the query on the Contacts dbset is obviously returning all the columns. How should I narrow the columns from 20 to 2 in order to have a lighter query to database?
I know I could do a Stored Procedure or View in database just for this cases, and use this for DropDownList population but... there is another way of doing it using directly the Entity Framework?
This happens in several entities, not just Contacts, so I would like to have a clear strategy for handling this scenaries.
You could add a .Select on to your query:
new SelectList(db.Contacts.AsNoTracking()
.Where(x => x.idTenant == CurrentTenantID)
.Select(x => new { x.ContactId, x.Name })
, "ContactId", "Name");

NHibernate Fluent Join mapping for many to one relationship

I'm trying to fetch a collection of read-only objects from NHibernate where all the properties come from a single table (Answers), with the exception of one property that comes from another table (Questions) in a many to one relationship. The fact it's two tables is an implementation detail that I want to hide, so I want the repository to return a sensible aggregate. The trouble is this requires I have two classes, one for each table, that NHibernate returns and then I have to select/map that into a third class that my repository returns. This feels a bit rubbish so instead I was hoping to have a mapping that joins the two tables for me but maps all the columns onto a single class. My mapping looks like this:
public QuestionAnswerMap()
{
ReadOnly();
Table("Question");
Id(x => x.Id).Column("questionId").GeneratedBy.Identity();
Map(x => x.AnswerShortCode).Column("AnswerShortCode");
Join("Answers", join =>
{
join.Fetch.Join();
join.KeyColumn("questionId").Inverse();
join.Map(x => x.QuestionId).Column("QuestionId");
join.Map(x => x.AnswerId).Column("AnswerId");
join.Map(x => x.MemberId).Column("MemberId");
});
}
The SQL this generates looks perfect and returns exactly what I want, but when there are multiple Answers that join to the same row in the Questions table, NHibernate seems to map them to objects wrongly - I get the right number of results, but all the Answers that have a common Question are hydrated with the first row in sql result for that Question.
Am I doing this the right way? NH is generating the right SQL, so why is it building my objects wrong?
because Join was meant to be this way. It assumes a one to one association between the two tables which are not the case.
Instead of a mapped Entity i would prefere a on the fly Dto for this:
var query = session.Query<Answer>()
.Where(answer => ...)
.Select(answer => new QuestionAnswer
{
QuestionId = answer.Question.Id,
AnswerShortCode = answer.Question.AnswerShortCode,
AnswerId = answer.Id,
MemberId = answer.MemberId,
});
return query.ToList();

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();

nhibernate queries SubQueryExpression

Can someone explain me what are NHibernate SubQueryExpression based queries. Any links with concrete examples are very welcome.
Thanks
Update:
Let's say that I have one entity named Beach. That beach can have many images. I want to select Beach entity and it;s first image from Images collection. I want to carry arround only that selected image object, or if I select only second object to carry only that object.
I do not want to access like Images.First() cause that will initialize all collection, if you need more info, plase ask.
var query = session.QueryOver(() => vehicleAlias)
.Left.JoinAlias(() => vehicleAlias.VehicleRegistrations, () => vehicleRegistrationAlias)
.WithSubquery.WhereProperty(() => vehicleRegistrationAlias.RegistrationExpiryDate).Eq(
QueryOver.Of(() => vehicleRegistrationAlias2)
.Where(() => vehicleRegistrationAlias2.Vehicle.Id == vehicleAlias.Id)
.Select(Projections.Max<VehicleRegistration>(ps => ps.RegistrationExpiryDate)));
query.Left.JoinAlias(() => vehicleRegistrationAlias.VehicleRegistrants, () => vehicleRegistrantAlias)
.Where(() => vehicleRegistrantAlias.Client.Id == clientId);
This is a subquery I just wrote for my work that took me a while to write. I don't really know what you are asking in specific but here is a sample. If you have any questions on it let me know.
.Select(Projections.Max(ps => ps.RegistrationExpiryDate))) This line does all the work in the sub query. It selects the most recent vehicle registration. Vehicle registration alias 2 is the object being queried as a sub query.
So this will pull back only the current vehicle registration for a vehicle. One vehicle may have many vehicle registrations. Its the .Select statement that can be modified into something like .OrderById.Desc.SelectTop(1) or something like that.
I hope this edit helps.

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

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.