0

NHibernate を使用して Web アプリからクエリを実行している階層データを保持するテーブルがあります。それはかなり簡単です

CREATE TABLE [dbo].[Relationships](
    [RelationshipId] [uniqueidentifier] NOT NULL,
    [ParentId] [uniqueidentifier] NULL,
    [ParentTypeId] [uniqueidentifier] NULL,
    [ChildId] [uniqueidentifier] NOT NULL,
    [ChildTypeId] [uniqueidentifier] NOT NULL
)

このテーブルから情報をクエリするために、Common Table Expressions (略して CTE) と呼ばれる SQL Server (2005 年以降) の機能を使用しています。上記のようなテーブルに非常に役立つ再帰クエリを作成できます。

WITH Ancestors(RelationshipId, ParentId, ChildId) 
AS 
(
    SELECT r.RelationshipId, r.ParentId, r.ChildId 
        FROM Relationships r 
        WHERE ChildId = :objectId 
    UNION ALL 
    SELECT r.RelationshipId, r.ParentId, r.ChildId 
        FROM Relationships r 
            INNER JOIN Ancestors 
                ON Ancestors.ParentId = r.ChildId 
) 
SELECT RelationshipId, ParentId, ChildId FROM Ancestors

さて、これは素晴らしいことであり、パフォーマンスはそれほど悪くはありませんが、これを使用してツリーを上る先祖を特定しようとすると、またはさらに悪いことに、同様のクエリを使用して子孫を特定しようとすると、負担がかかる可能性があります。

ここで、このクエリの結果を単純にキャッシュしたいのですがIndex was outside the bounds of the array..SetCacheable(true). キャッシュのサポートを削除すると、クエリは正常に機能します。

への呼び出しからキャッシング サポートを削除すると、クエリは正常に機能しSession.CreateSQLQuery()ます。オンラインで原因を調べてみましたが、見つかった結果の中でコンセンサスが見つかりませんでした。

なぜうまくいかないのか知りたいのですが、nHibernate の CTE でキャッシングを機能させるための回避策を見つけることにもっと興味がありますか?

4

2 に答える 2

0

単純に次のことを行うことになりました。私はまだキャッシングをテストしていませんが、CTE が提供する柔軟性のために、それを犠牲にしなければならないかもしれません。

const string query = "WITH Ancestors(RelationshipId, ParentId, ChildId) " +
                        "AS " +
                        "( SELECT por.RelationshipId, por.ParentId, por.ChildId " +
                        "FROM PseudoObjectRelationships por WHERE ChildId = :objectId " +
                        "UNION ALL " +
                        "SELECT por.RelationshipId, por.ParentId, por.ChildId " +
                        "FROM PseudoObjectRelationships por " +
                        "INNER JOIN Ancestors " +
                        "ON Ancestors.ParentId = por.ChildId " +
                        ") " +
                        "SELECT RelationshipId, ParentId, ChildId FROM Ancestors";

return ((DynamicObjectRepository<TObject>)dynamicObjectRepository).CreateSQLQuery(query)
        .SetGuid("objectId", objectId)
        .SetResultTransformer(Transformers.AliasToBean<Relationship>())
        .List<Relationship>();
于 2012-11-29T00:39:56.920 に答える
0

エラーの詳細を確認することもできますが、代わりに名前付きクエリを使用できると思います... http://geekswithblogs.net/TStewartDev/archive/2010/04/11/caching-nhibernate-named-queries .aspx

XML で SQL を定義し (必要に応じて SP を呼び出します)、Resultset を宣言します。あなたは呼び出しから何を期待するかをnhibernateに伝えているので、それをキャッシュする方法を解決できると思います(推測)。私は通常dtoに変換します。

Db が変更された場合は、キャッシュを手動でクリアする必要があることに注意してください。エンティティを使用していないため、基になるデータが変更された場合は自分でキャッシュをクリアする必要があります。

于 2012-10-28T00:04:11.737 に答える