공식으로 매핑 된 계산 된 값 (예 : 순위)을 포함하여 검색에 대한 nhibernate 캐싱에 미치는 영향

StackOverflow https://stackoverflow.com/questions/1627707

문제

nhibernate에서 공식을 사용하여 계산 된 속성을 정의 할 때, 특히 쿼리 캐싱과 관련하여 쿼리 제한에 따라 공식이 결과를 변화시킬 때의 의미는 무엇입니까?

보다 구체적으로 다음 간단한 C# 클래스를 고려하십시오.

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 매핑과 맵핑 :

<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, 다음과 같은 방법으로 쿼리했습니다.

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 매핑에서 그러한 공식을 사용할 때 다른 우려가 있습니까?

편집하다:

내 특정한 경우 "Entity"는 일류 비즈니스 엔티티가 아니라 일종의 메타 엔티티라는 점에 주목할 가치가 있습니다. 다른 일류 엔티티를 통해 인덱스 된 데이터베이스보기에 매핑되며 검색에만 사용됩니다 (Session.Load (ID) 호출은 실제로 진행되며 실제로 실제로 발생해서는 안됩니다).

그리고 만약 거기 있다면 ~이다 캐싱에 대한 시사는 내가 의심되는 바와 같이, 잠재적 인 문제를 피하기 위해 유사한 사용 사례에 어떤 대안이 존재할 수 있습니까?

도움이 되었습니까?

해결책

추가 실험 후 : 예, 캐시 영향이 일관되지 않은 결과가 있습니다. nhibernate는 공식이 동일한 식별자로 엔티티 결과에 대한 쿼리 사이의 값을 변경할 수 있음을 자동으로 알 수 없습니다 (그렇지 않다고 가정).

질문에있는 클래스 매핑을 사용하면 순위가 나머지 엔티티 데이터에 저장 될 수 있습니다. 이렇게하면 후속 쿼리가 쿼리가 실행되는 대신 다른 쿼리에서 순위 값을 반환하여 예상대로 순차적이지 않은 순위를 가질 수 있습니다.

nhibernate는 분리되어 있습니다 질문 그리고 엔티티 캐시 (실제로 두 개의 엔티티 캐시가 있습니다 - 세션 캐시 그리고 두 번째 레벨 엔티티 캐시) 그리고 그 영향은 어떤 것이 사용되는지에 따라 다릅니다.

쿼리 캐시가 활성화되지 않은 경우 동일한 세션 내에서 결과를 공유하지만 다른 순위가 다른 두 개의 다른 쿼리를 작성하면 잘못된 순위 값을 수신 할 수 있습니다. 이 경우 동일한 세션의 두 번째 쿼리는 첫 번째 쿼리에서 이미 세션에서 엔티티 데이터를 재정의하지 않으므로 (해당 작업 단위에 대해 변경되었을 수 있기 때문에) 반환 된 순위 값은 첫 번째와 동일합니다. 두 번째 쿼리의 실제 순위가 아닌 쿼리. 첫 번째 쿼리에서 결과를 발표합니다 ~해야 한다 이 문제를 피하십시오 (그러나 권장 솔루션은 아닙니다. 아래 참조).

쿼리 캐시시 ~이다 다른 쿼리가 실행 된 후 동일한 쿼리를 반복 할 때 활성화 된 순위 값도 수신 할 수 있습니다. 이 경우 첫 번째 쿼리 실행은 결과 식별자를 쿼리 캐시 및 엔티티 (순위와 함께)에 엔티티 캐시에 추가합니다. 인터리브 쿼리 (다른 세션에서 실행될 때)는 엔티티 캐시의 엔티티에 저장된 순위 값으로 변경 될 수 있습니다. 첫 번째 쿼리가 다시 실행되면 캐시 된 식별자는 캐시 된 엔티티를 조회하는 데 사용됩니다 (변경된 순위와 함께).


엔티티의 지속적인 값 만 포함하도록 엔티티를 변경함으로써 문제를 완전히 해결할 수 있습니다 (즉, 순위 제외). 그런 다음 쿼리의 경우 투영을 사용하여 식별자와 해당 쿼리의 순위를 추출합니다.

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 그리고 그 쿼리에 대한 관련 순위.

단일 쿼리 대신 두 개의 개별 쿼리를 사용해야한다는 것은 약간 성가신 일이지만, 이것은 적절한 방식으로 캐시를 사용하는 유일한 방법 인 것 같습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top