将投影添加到 NHibernate 标准会阻止其执行默认实体选择

发布于 2024-08-09 22:46:34 字数 1084 浏览 6 评论 0原文

我正在编写一个 NHibernate 标准来选择支持分页的数据。我使用 SQL Server 2005(+) 中的 COUNT(*) OVER() 表达式来获取可用行的总数,如 Ayende Rahien 建议。我需要这个数字才能计算出总共有多少页。该解决方案的优点在于我不需要执行第二个查询来获取行计数。

但是,我似乎无法编写工作标准(Ayende 仅提供 HQL 查询)。

这是一个 SQL 查询,它显示了我想要的内容,并且运行得很好。请注意,我故意省略了实际的分页逻辑来关注问题:

SELECT Items.*, COUNT(*) OVER() AS rowcount
FROM Items

这是 HQL:

select
    item, rowcount()
from 
    Item item

请注意,rowcount() 函数是在自定义 NHibernate 方言中注册的,并解析为 COUNT(* ) SQL 中的 OVER()。

要求是使用条件来表达查询。不幸的是,我不知道如何正确处理:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(
       Projections.SqlFunction("rowcount", NHibernateUtil.Int32));

每当我添加投影时,NHibernate 都不会选择 item (就像没有投影时一样),只是选择 rowcount()< /code> 虽然我真的需要两者。另外,我似乎无法将 item 作为一个整体来投影,只能投影它的属性,而且我真的不想列出所有这些属性。

我希望有人能解决这个问题。不管怎样,谢谢。

I'm writing an NHibernate criteria that selects data supporting paging. I'm using the COUNT(*) OVER() expression from SQL Server 2005(+) to get hold of the total number of available rows, as suggested by Ayende Rahien. I need that number to be able to calculate how many pages there are in total. The beauty of this solution is that I don't need to execute a second query to get hold of the row count.

However, I can't seem to manage to write a working criteria (Ayende only provides an HQL query).

Here's an SQL query that shows what I want and it works just fine. Note that I intentionally left out the actual paging logic to focus on the problem:

SELECT Items.*, COUNT(*) OVER() AS rowcount
FROM Items

Here's the HQL:

select
    item, rowcount()
from 
    Item item

Note that the rowcount() function is registered in a custom NHibernate dialect and resolves to COUNT(*) OVER() in SQL.

A requirement is that the query is expressed using a criteria. Unfortunately, I don't know how to get it right:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(
       Projections.SqlFunction("rowcount", NHibernateUtil.Int32));

Whenever I add a projection, NHibernate doesn't select item (like it would without a projection), just the rowcount() while I really need both. Also, I can't seem to project item as a whole, only it's properties and I really don't want to list all of them.

I hope someone has a solution to this. Thanks anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

时光匆匆的小流年 2024-08-16 22:46:34

我认为这在 Criteria 中是不可能的,它有一些限制。

您可以在后续查询中获取 id 并加载项目:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(Projections.ProjectionList()
       .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32))
       .Add(Projections.Id()));

如果您不喜欢它,请使用 HQL,您也可以在那里设置最大结果数:

IList<Item> result = Session
    .CreateQuery("select item, rowcount() from item where ..." )
    .SetMaxResult(100)
    .List<Item>();

I think it is not possible in Criteria, it has some limits.

You could get the id and load items in a subsequent query:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(Projections.ProjectionList()
       .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32))
       .Add(Projections.Id()));

If you don't like it, use HQL, you can set the maximal number of results there too:

IList<Item> result = Session
    .CreateQuery("select item, rowcount() from item where ..." )
    .SetMaxResult(100)
    .List<Item>();
燕归巢 2024-08-16 22:46:34

使用创建多条件。

这样,您只需对数据库进行一次点击即可执行 2 个简单的语句。

Use CreateMultiCriteria.

You can execute 2 simple statements with only one hit to the DB that way.

对你再特殊 2024-08-16 22:46:34

我想知道为什么需要使用 Criteria。你不能使用session.CreateSQLQuery吗?如果您确实必须在一个查询中执行此操作,我建议拉回 Item 对象和计数,例如:

select {item.*}, count(*) over() 
from Item {item}

...这样您就可以从查询中获取 Item 对象以及计数。如果您遇到 Hibernate 缓存问题,您还可以配置与本机查询关联的查询空间(实体/表缓存),以便自动清除过时的查询缓存条目。

I am wondering why using Criteria is a requirement. Can't you use session.CreateSQLQuery? If you really must do it in one query, I would have suggested pulling back the Item objects and the count, like:

select {item.*}, count(*) over() 
from Item {item}

...this way you can get back Item objects from your query, along with the count. If you experience a problem with Hibernate's caching, you can also configure the query spaces (entity/table caches) associated with a native query so that stale query cache entries will be cleared automatically.

红玫瑰 2024-08-16 22:46:34

如果我正确理解你的问题,我就有一个解决方案。我在同样的问题上挣扎了很多。

让我快速描述一下我遇到的问题,以确保我们意见一致。我的问题归结为分页。我想在 UI 中显示 10 条记录,但我还想知道与过滤条件匹配的记录总数。我想使用 NH criteria API 来完成此任务,但是当添加行数投影时,我的查询不再起作用,并且我不会得到任何结果(我不记得具体的错误,但听起来像你的正在得到)。

这是我的解决方案(从我当前的生产代码复制并粘贴)。请注意,“SessionError”是我正在检索分页数据的业务实体的名称,根据 3 个过滤条件:IsDev、IsRead 和 IsResolved。

ICriteria crit = CurrentSession.CreateCriteria(typeof (SessionError))
    .Add(Restrictions.Eq("WebApp", this));

if (isDev.HasValue)
    crit.Add(Restrictions.Eq("IsDev", isDev.Value));

if (isRead.HasValue)
    crit.Add(Restrictions.Eq("IsRead", isRead.Value));

if (isResolved.HasValue)
    crit.Add(Restrictions.Eq("IsResolved", isResolved.Value));

// Order by most recent
crit.AddOrder(Order.Desc("DateCreated"));

// Copy the ICriteria query to get a row count as well
ICriteria critCount = CriteriaTransformer.Clone(crit)
    .SetProjection(Projections.RowCountInt64());
critCount.Orders.Clear();

// NOW add the paging vars to the original query
crit = crit
    .SetMaxResults(pageSize)
    .SetFirstResult(pageNum_oneBased * pageSize);

// Set up a multi criteria to get your data in a single trip to the database
IMultiCriteria multCrit = CurrentSession.CreateMultiCriteria()
    .Add(crit)
    .Add(critCount);

// Get the results
IList results = multCrit.List();

List<SessionError> sessionErrors = new List<SessionError>();
foreach (SessionError sessErr in ((IList)results[0]))
    sessionErrors.Add(sessErr);

numResults = (long)((IList)results[1])[0];

因此,我创建了我的基本标准,并带有可选的限制。然后我克隆它,并将行计数投影添加到克隆条件中。请注意,我在添加分页限制之前克隆了它。然后,我设置一个 IMultiCriteria 来包含原始和克隆的 ICriteria 对象,并使用 IMultiCriteria 执行它们。现在,我有了来自原始 ICriteria 的分页数据(并且我只通过网络拖动了所需的数据),以及有多少实际记录符合我的条件的原始计数(对于显示或创建分页链接等很有用)。这个策略对我来说效果很好。我希望这有帮助。

If I understand your question properly, I have a solution. I struggled quite a bit with this same problem.

Let me quickly describe the problem I had, to make sure we're on the same page. My problem came down to paging. I want to display 10 records in the UI, but I also want to know the total number of records that matched the filter criteria. I wanted to accomplish this using the NH criteria API, but when adding a projection for row count, my query no longer worked, and I wouldn't get any results (I don't remember the specific error, but it sounds like what you're getting).

Here's my solution (copy & paste from my current production code). Note that "SessionError" is the name of the business entity I'm retrieving paged data for, according to 3 filter criterion: IsDev, IsRead, and IsResolved.

ICriteria crit = CurrentSession.CreateCriteria(typeof (SessionError))
    .Add(Restrictions.Eq("WebApp", this));

if (isDev.HasValue)
    crit.Add(Restrictions.Eq("IsDev", isDev.Value));

if (isRead.HasValue)
    crit.Add(Restrictions.Eq("IsRead", isRead.Value));

if (isResolved.HasValue)
    crit.Add(Restrictions.Eq("IsResolved", isResolved.Value));

// Order by most recent
crit.AddOrder(Order.Desc("DateCreated"));

// Copy the ICriteria query to get a row count as well
ICriteria critCount = CriteriaTransformer.Clone(crit)
    .SetProjection(Projections.RowCountInt64());
critCount.Orders.Clear();

// NOW add the paging vars to the original query
crit = crit
    .SetMaxResults(pageSize)
    .SetFirstResult(pageNum_oneBased * pageSize);

// Set up a multi criteria to get your data in a single trip to the database
IMultiCriteria multCrit = CurrentSession.CreateMultiCriteria()
    .Add(crit)
    .Add(critCount);

// Get the results
IList results = multCrit.List();

List<SessionError> sessionErrors = new List<SessionError>();
foreach (SessionError sessErr in ((IList)results[0]))
    sessionErrors.Add(sessErr);

numResults = (long)((IList)results[1])[0];

So I create my base criteria, with optional restrictions. Then I CLONE it, and add a row count projection to the CLONED criteria. Note that I clone it before I add the paging restrictions. Then I set up an IMultiCriteria to contain the original and cloned ICriteria objects, and use the IMultiCriteria to execute both of them. Now I have my paged data from the original ICriteria (and I only dragged the data I need across the wire), and also a raw count of how many actual records matched my criteria (useful for display or creating paging links, or whatever). This strategy has worked well for me. I hope this is helpful.

故人爱我别走 2024-08-16 22:46:34

我建议通过在会话中调用 SetResultTransformer() 来调查自定义结果转换器。

I would suggest investigating custom result transformer by calling SetResultTransformer() on your session.

挽心 2024-08-16 22:46:34

在类映射中创建公式属性:

<property name="TotalRecords" formula="count(*) over()" type="Int32" not-null="true"/>;

IList<...> result = criteria.SetFirstResult(skip).SetMaxResults(take).List<...>();
totalRecords = (result != null && result.Count > 0) ? result[0].TotalRecords : 0;
return result;

Create a formula property in the class mapping:

<property name="TotalRecords" formula="count(*) over()" type="Int32" not-null="true"/>;

IList<...> result = criteria.SetFirstResult(skip).SetMaxResults(take).List<...>();
totalRecords = (result != null && result.Count > 0) ? result[0].TotalRecords : 0;
return result;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文