【问题标题】:NHibernate get first x distinct results does not get me x results?NHibernate 得到第一个 x 不同的结果不会让我得到 x 个结果?
【发布时间】:2012-08-21 15:27:56
【问题描述】:

我有一个这样的 ICriteria 查询:

var contentCriteria = DetachedCriteria.For<InvoiceItem>();
var countCriteria = DetachedCriteria.For<InvoiceItem>();

if (model.CurrentPage <= 0) model.CurrentPage = 1;

if (model.OnlyShowErrors)
{
    contentCriteria.Add(Restrictions.Not(Restrictions.Eq("TroubleClass", TroubleClasses.Success)));
    countCriteria.Add(Restrictions.Not(Restrictions.Eq("TroubleClass", TroubleClasses.Success)));
}

if (!string.IsNullOrEmpty(model.BatchId))
{
    contentCriteria.Add(Restrictions.Eq("BatchId", model.BatchId));
    countCriteria.Add(Restrictions.Eq("BatchId", model.BatchId));
}

if (model.DocumentStartDate != null)
{
    contentCriteria.Add(Restrictions.Ge("DocumentDate", model.DocumentStartDate));
    countCriteria.Add(Restrictions.Ge("DocumentDate", model.DocumentStartDate));
}

if (model.DocumentEndDate != null)
{
    contentCriteria.Add(Restrictions.Le("DocumentDate", model.DocumentEndDate));
    countCriteria.Add(Restrictions.Le("DocumentDate", model.DocumentEndDate));
}

if (!string.IsNullOrEmpty(model.VendorId))
{
    contentCriteria.Add(Restrictions.Eq("VendorId", model.VendorId));
    countCriteria.Add(Restrictions.Eq("VendorId", model.VendorId));
}


using (var session = GetSession())
{

    var countC = countCriteria.GetExecutableCriteria(session)
        .SetProjection(Projections.CountDistinct("RecordId"));

    var contentC = contentCriteria
        .AddOrder(Order.Desc("PersistedTimeStamp"))
        .GetExecutableCriteria(session)
        .SetResultTransformer(Transformers.DistinctRootEntity)
        .SetFirstResult((model.CurrentPage * model.ItemsPerPage) - model.ItemsPerPage)
        .SetMaxResults(model.ItemsPerPage);

    var mq = session.CreateMultiCriteria()
        .Add("total", countC)
        .Add<InvoiceItem>("paged", contentC);

    model.Invoices = ((IEnumerable<InvoiceItem>)mq.GetResult("paged"));
    model.Invoices = model.Invoices
        .OrderBy(x => x.PersistedTimeStamp);

    model.TotalItems = (int)(mq.GetResult("total") as System.Collections.ArrayList)[0];
}
return model;

这会返回结果,但我希望结果以model.ItemsPerPage 为一组,但很少出现。我认为.SetResultTransformer(Transformers.DistinctRootEntity) 转换是在.SetMaxResults(model.ItemsPerPage) 限制之后运行的,我不知道为什么或如何解决它。有人可以请教我吗?

【问题讨论】:

  • NHibernate 生成的实际查询是什么?
  • 通常在执行左外连接(eager fetching)时使用 .SetResultTransformer(Transformers.DistinctRootEntity)

标签: c# hibernate nhibernate postgresql nhibernate-criteria


【解决方案1】:

您需要查看 NHibernate 生成的 SQL,因为这本质上不是 NHibernate 错误,而是当 ROWNUMDISTINCT 一起应用时 SQL 查询的行为。这一直是我们已知问题列表中的一个问题。

以下网址可能会启发您...

ROW NUMBER vs DISTINCT

How ROWNUM works

【讨论】:

  • 你能检查下发出的 SQL 吗?
【解决方案2】:

所以这与this blog post 中的内容直接相关。此外,我遇到了 PostgreSQL 特定于平台的复杂性,它不允许 DISTINCT 有序集由不在 SELECT 列表中的东西排序。最终,我不得不对数据库进行两次调用,如下所示:

using (var session = GetSession())
{
    //I honestly hope I never have to reverse engineer this mess.  Pagination in NHibernate
    //when ordering by an additional column is a nightmare.
    var countC = countCriteria.GetExecutableCriteria(session)
        .SetProjection(Projections.CountDistinct("RecordId"));

    var contentOrdered = contentCriteria
        .SetProjection(Projections.Distinct(
            Projections.ProjectionList()
                .Add(Projections.Id())
                .Add(Projections.Property("PersistedTimeStamp"))
                ))
        .AddOrder(Order.Desc("PersistedTimeStamp"))
        .SetFirstResult((model.CurrentPage * model.ItemsPerPage) - model.ItemsPerPage)
        .SetMaxResults(model.ItemsPerPage);

    var contentIds = contentOrdered.GetExecutableCriteria(session)
        .List().OfType<IEnumerable<object>>()
        .Select(s => (Guid)s.First())
        .ToList();

    var contentC = DetachedCriteria.For<InvoiceItem>()
        .Add(Restrictions.In("RecordId", contentIds))
        .SetResultTransformer(Transformers.DistinctRootEntity);

    var mq = session.CreateMultiCriteria()
        .Add("total", countC)
        .Add("paged", contentC);

    model.Invoices = (mq.GetResult("paged") as System.Collections.ArrayList)
        .OfType<InvoiceItem>()
        .OrderBy(x => x.PersistedTimeStamp);

    model.TotalItems = (int)(mq.GetResult("total") as System.Collections.ArrayList)[0];
}
return model;

这并不漂亮,但它有效;我认为 NHibernate 的人们需要努力解决这个问题,让它变得更容易一些。

【讨论】:

    猜你喜欢
    • 2018-06-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多