搜索结果对NHibernate缓存的影响,搜索结果包括以公式(例如等级)映射的计算值 [英] Impact on NHibernate caching for searches with results including calculated value mapped as a formula (e.g. rank)

查看:63
本文介绍了搜索结果对NHibernate缓存的影响,搜索结果包括以公式(例如等级)映射的计算值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在NHibernate中使用公式定义计算所得的属性时,公式根据查询限制(尤其是查询缓存)改变其结果的含义是什么?

When defining a calculated property using a formula in NHibernate, what are the implications for when the formula varies its result depending on the query restrictions, especially with regards to query caching?

更具体地说,考虑以下简单的C#类:

More specifically, consider the following simple C# class:

public class Entity
{
    public Entity() { }
    public virtual int Id { get; protected set; }
    public virtual string Key { get; protected set; }
    public virtual string Value { get; protected set; }
    public virtual int Rank { get; protected set; }
}

映射了以下简单的NHibernate映射:

Mapped with the following simple NHibernate mapping:

<class name="Entity" mutable="false">
    <id name="Id">
        <generator class="native">
    </id>
    <property name="Key"/>
    <property name="Value"/>
    <property name="Rank" formula="row_number() over(order by value)">
</class>

在会话工厂中运行,并且将hibernate.cache.use_query_cache选项设置为true,并通过以下方式查询:

Running with a session factory with hibernate.cache.use_query_cache option set to true, and queried in the following ways:

ICriteria criteria = session.CreateCriteria(typeof(Entity));
criteria.SetCacheable(true);
criteria.SetCacheRegion("SearchResults");
IList<Entity> queryResult1 = criteria.List<Entity>();

criteria = session.CreateCriteria(typeof(Entity));
criteria.SetCacheable(true);
criteria.SetCacheRegion("SearchResults");
criteria.Add(Restrictions.Like("Key", "a", MatchMode.Anywhere));
IList<Entity> queryResult2 = criteria.List<Entity>();

Entity directResult = session.Load<Entity>(id);

NHibernate对于返回的实体会表现出合理的行为吗?还是由于查询缓存,一个缓存查询的等级"值会污染另一个查询的等级"值吗?在NHibernate映射中使用这样的公式时还有其他问题吗?

Will NHibernate behave in a reasonable manner for the returned Entities? Or could the "Rank" value from one cached query pollute the Rank value of another query due to the query cache? Are there any other concerns when using such a formula in NHibernate mappings?

在我的特殊情况下,实体"不是一流的业务实体,而是某种元实体,这也可能值得注意.它映射到其他一等实体上的索引数据库视图,并且专门用于搜索(session.Load(id)调用是人为设计的,实际上不应该实际发生).

It might also be worth noting that in my particular case, "Entity" is not a first-class business entity, but sort of a meta-entity. It maps to an indexed database view over other first-class entities and is used exclusively for searching (the session.Load(id) call is contrived and should never actually happen in practice).

而且,如我所怀疑的那样,如果缓存涉及到 ,那么对于类似的用例,可以使用哪些替代方案来避免潜在的问题?

And, if there are implications to caching, as I suspect, what alternatives might exist for a similar use-case to avoid potential problems?

推荐答案

进一步实验之后:是的,存在缓存含义,可能导致结果不一致; NHibernate无法自动知道该公式可以更改具有相同标识符的实体结果的查询之间的值(并假设不会).

After further experimentation: Yes, there are cache implications that could result in inconsistent results; NHibernate cannot automatically know that the formula could change values between queries for entity results with the same identifier (and assumes it won't).

具有与问题中的类对应的类映射将导致该排名与其余实体数据一起存储.这样一来,后续查询最终可能会从其他查询返回排名值,而不是正在运行的查询,从而使排名不符合预期.

Having a class mapping as those in the question would result in the rank being stored with the rest of the entity data. This makes it possible that a subsequent query will end up returning a rank value from some other query rather than the query being run and thus have ranks that are not sequential as expected.

NHibernate具有单独的查询和实体缓存(有实际上是两个实体缓存-会话缓存二级实体缓存),其影响取决于哪些是正在使用.

NHibernate has separate query and entity caches (there are actually two entity caches - the session cache and the second level entity cache) and the impacts depend on which ones are being used.

未启用查询缓存时,如果执行以下操作,则可能会收到不正确的排名值 同一会话中的两个不同查询,它们共享一个结果,但排名不同.在这种情况下,同一会话的第二个查询将不会覆盖第一个查询中已存在于会话中的实体数据(因为它可能已针对该工作单元进行了更改),因此返回的排名值将与第一个查询相同查询,而不是第二个查询的实际排名.从第一个查询中逐出结果应该避免此问题(但不是推荐的解决方案;请参见下文)

When the query cache is not enabled, incorrect rank values can be received if you make two different queries within the same session that share a result but with different ranks. In this case, the second query of the same session will not override the entity data already in the session from the first query (since it might have changed for that unit of work), so the rank value returned will be the same from the first query rather than the actual rank from the second query. Evicting the results from the first query should avoid this issue (but is not the recommended solution; see below)

启用查询缓存 时,在执行其他一些具有不同等级结果的查询后重复相同的查询时,也会收到不正确的等级值.在这种情况下,第一次查询执行将结果标识符添加到查询缓存中,并将实体(及其排名)添加到实体缓存中.交错查询(在另一个会话中运行时)可能会导致与实体存储在实体缓存中的等级值发生变化.重新执行第一个查询时,缓存的标识符用于查找缓存的实体(具有更改的等级).

When the query cache is enabled, incorrect rank values can also be received when repeating the same query after some other query has executed that had a result with a different rank. In this case, the first query execution adds the result identifiers to the query cache and the entities (with their rank) to the entity cache. The interleaved query (when run in another session) could result in a change to the rank value stored with the entity in the entity cache. When the first query is re-executed, the cached identifiers are used to lookup the cached entities (with the changed ranks).

可以通过将实体更改为仅包含实体的持久值(即不包括等级)来完全解决该问题.然后,对于查询,使用投影来提取该查询的标识符和等级:

The problem can be addressed completely by changing the entity to only include the persisted values for the entity (i.e. excluding the rank). Then, for the query, use a projection to extract the identifier and the rank for that query:

ICriteria criteria = session.CreateCriteria(typeof(Entity));
criteria.SetCacheable(true);
criteria.SetCacheRegion("SearchResults");
criteria.SetProjection
    (Projections.Id(), 
     Projections.SqlProjection("row_number() over(order by value) as Rank",
                               new[] { "Rank" },
                               new[] { NHibernateUtil.Int32 }));

在这种情况下,由于排名是一种值类型,因此查询缓存将在特定于该 查询的查询结果标识符旁边存储该排名.然后,使用第二个查询,使用投影的标识符查找实体值.棘手的是,在执行实体查询时,您将希望避免N+1类型问题,并且您将需要创建另一个数据结构来与该查询的Entity及其关联等级相结合.

In this case, since the rank is a value type, the query cache will store the rank along side the query result identifiers for that specific query. Then, using a second query, lookup the entity values using the projected identifiers. The tricky part is that you'll want to avoid an N+1 type issue when performing the entity query and you will need to create another data structure to marry the Entity and its associated rank for that query.

有点麻烦,您必须使用两个单独的查询而不是单个查询,但这似乎是以适当方式使用缓存的唯一方法.

It's a little annoying that you have to use two separate queries rather than a single query, but this seems to be the only way to use the caches in an appropriate manner.

这篇关于搜索结果对NHibernate缓存的影响,搜索结果包括以公式(例如等级)映射的计算值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆