简体   繁体   English

结合NHibernate中Query / QueryOver和DetachedCriteria的工作原理

[英]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. 在我当前的项目中,我开始使用NHibernate,并且基本上一切运行良好,直到需要将某个实体的完整对象树发送给我的服务使用者为止-急切地从服务器加载和发送的所有内容。

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) 如果我这样调用查询,我将得到正确的结果:(但是这会产生3个查询,至少,我得到了正确的结果)

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). (是的,它仍然会创建3个查询)。

For I definitelly need all the items of type ResultContent in Content populated. 因为我绝对需要在Content填充所有ResultContent类型的项目。 ResultContent has some collections of elements, that have their collections as well. ResultContent有一些元素的集合,也有它们的集合。 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: 我现在几乎整天都在处理NHibernate查询,并且几乎可以通过以下查询实现正确的行为:

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. 通过这种方法,我得到了5个结果,但是Content集合的填充没有超出第一个元素。 And for the DataCollection in Numerics, there only are 5 elements queried, even though it should be somewhere near 500 items pulled. 对于以数字表示的DataCollection,仅查询了5个元素,即使应该拉近500个项目也是如此。

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. 我在FetchModes上玩了很多游戏,并且开始认为我将无法实现我将来所需要的东西。 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)? 我是否应该使用HQL(我从未使用过,所以我想我会更加努力)?

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. 注意:我在Google上搜索了很多,并尝试了很多东西,但是就NHibernate和sql而言,我认为自己是一个菜鸟。 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. DataEntry和DataDescription类仅包含Id,Date和字符串或布尔值。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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