简体   繁体   中英

Combine workings of Query / QueryOver and DetachedCriteria in NHibernate

In my current project, I started using NHibernate and basically everything works nicely, up to a point, where I need to send complete object tree for some entity to the consumer of my service = everything eagerly loaded and sent from the server.

And I want my queries to be as fast as possible.

The search criteria is rather simple: the complete newest result object for the specified product and the specified department.

If i call my query like this, I am getting the correct result: (however this produces 3 queries, still, at least I am getting the correct result)

Result res = session.QueryOver<Result>()
                 .Where(x => x.Product == product)
                 .Where(x => x.Department == department)
                 .OrderBy(x => x.Date).Desc
                 .Take(1).SingleOrDefault();

However, such result is not eagerly loaded with all the child collections. (and yes, it still creates 3 queries).

For I definitelly need all the items of type ResultContent in Content populated. ResultContent has some collections of elements, that have their collections as well. I desperately need all those collections fully populated with all the child elements and child elements of its child elements and so on.

I played with NHibernate queries nearly whole day now and am nearly achieving correct behavior with query like this:

var resultCriteria = DetachedCriteria.For<Result>();
resultCriteria.SetFetchMode("Product", FetchMode.Eager);
resultCriteria.SetFetchMode("Department", FetchMode.Eager);
resultCriteria.SetFetchMode("Content", FetchMode.Join);
resultCriteria.SetFetchMode("Source", FetchMode.Join);
resultCriteria.SetFetchMode("Content.Numerics", FetchMode.Eager);
resultCriteria.SetFetchMode("Content.Numerics.DataCollection", FetchMode.Join);
resultCriteria.SetFetchMode("Content.Numerics.DataDescription", FetchMode.Join);
resultCriteria.SetFetchMode("Content.Numerics.DataDescription.DescriptionSource", FetchMode.Eager);
resultCriteria.SetMaxResults(5);
var relevantResults = resultCriteria.GetExecutableCriteria(session).List<Result>();

With this approach, I am getting 5 Results, but the Content collection is not populated further than the first element. And for the DataCollection in Numerics, there only are 5 elements queried, even though it should be somewhere near 500 items pulled.

I Played with the FetchModes quite a lot and am starting to think that I will not achieve what I need nowhere near in the future. Could you please hint me in the proper direction how I could combine those 2 approaches properly?

Should I use HQL (I never did, so I think I would struggle even more)?

Note: I googled quite a lot and tried a lot of things, but as far as NHibernate and sql goes, I consider myself quite a noob. I will try improving my skills, but the time pressure now tends towards asking a question.

The other relevant classes look like this (so that you can see which class holds a collection of what, lots of simplifications applied of course)

public class Result
{
    public virtual long Id { get; protected set; }
    public virtual Product Product { get; set; }
    public virtual Department Department { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual ISet<ResultContent> Content { // getters and setters }
    public virtual ISet<ResultSource> Source { // getters and setters }
}

public class Product
{
    public virtual short Id { get; protected set; }
    public virtual string Name { get; set; }
    public virtual string Code { get; set; }
    public virtual string Description { get; set; }
}

public class Department
{
    public virtual short Id { get; protected set; }
    public virtual string Name { get; set; }
    public virtual string Code { get; set; }
    public virtual string Description { get; set; }
}

public class ResultContent
{
    public virtual Result Result { get; set; }
    public virtual Numerics Numerics { get; set; }
    public virtual long Revision { get; set; }
}

public class Numerics
{
    public virtual long Id { get; protected set; }
    public virtual string Name { get; set; }
    public virtual ISet<DataEntry> DataCollection { //getters and setters }
    public virtual ISet<DataDescription> DataDescription { //getters and setters}
}

DataEntry and DataDescription Classes are just holding Id, Date and either string or boolean value.

hi can you try it ,

    Result ra = null;
    Product pa = null;
    Department da = null;
    Result res = session.QueryOver<Result>(() => ra)
        .JoinAlias(() => ra.Product ,() => pa)
        .JoinAlias(() => ra.Department ,() => da)
        .Where(() => pa  == product)
        .Where(() => da == department)
        .OrderBy(() => ra.Date).Desc
        .Take(1).SingleOrDefault();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM