在NHibernate中缓存公用表表达式(CTE)查询

时间:2012-10-26 18:31:45

标签: sql-server nhibernate caching common-table-expression

我有一个表,其中包含我使用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的SQL Server功能(自2005年起),简称CTE。它允许我编写递归查询,这对于像上面那样的表非常有用。

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.,我会收到来自nHibernate .SetCacheable(true)的错误。如果我删除缓存支持,查询工作正常。

如果我从Session.CreateSQLQuery()调用中删除缓存支持,查询工作正常。现在我已经在网上尝试查找原因但我在找到的结果中没有找到共识。

因此,虽然我很好奇为什么它不起作用,但我更感兴趣的是找到一种解决方法来让缓存在nHibernate中使用我的CTE?

2 个答案:

答案 0 :(得分:0)

我可以看到错误的更多详细信息,但我会说你可以使用命名查询而不是... http://geekswithblogs.net/TStewartDev/archive/2010/04/11/caching-nhibernate-命名queries.aspx

在XML中定义SQL(如果需要,调用SP),然后声明Resultset。你告诉nhibernate从调用中得到什么,所以我认为它可以解决如何缓存它(猜测)。我通常转变为dto。

注意,如果Db发生变化,您需要手动清除缓存。您没有使用实体,因此如果基础数据已更改,您必须自己清除缓存。

答案 1 :(得分: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>();