NHibernate LINQ 添加查询提示

问题描述 投票:0回答:2

我正在尝试将“OPTION(RECOMPILE)”添加到我的一些 NHibernate 查询的末尾。我发现了以下帖子:

https://www.codewrecks.com/post/old/2011/07/use-sql-server-query-hints-with-nhibernate-hql-and-icriteria/

这描述了如何添加拦截器来附加 SQL。然而,他们使用 ICriteria,而我使用 LINQ 来查询我的数据。理想情况下,我希望能够这样说:

var query = session.Query<Foo>().OptionRecompile().ToList();

我想知道是否可以向 IQueryable 添加一个扩展方法,它将向查询中注入一些字符串,然后我可以在拦截器中检测到该字符串。这与上面文章中使用的方法类似,他们添加评论并进行检测。

欲了解更多信息。我之前处理过 LINQ 扩展,并且我知道您可以使用 HQL 生成器添加扩展属性/方法。但根据我的理解,这只能让我说:

var query = session.Query<Foo>().Where(f => f.Bar.OptionRecompile()).ToList();

这并不理想,看起来更像是一种黑客行为。如果有人可以提供帮助,我将不胜感激。谢谢

linq nhibernate linq-to-nhibernate
2个回答
6
投票

我最近也遇到了这个问题。我们想出了一个相当不错/强大的解决方案。重要的是它利用 Rhino.Commons.LocalData 来提供执行范围。

// First part
using System;
using System.Collections;
using System.Web;
using Rhino.Commons.LocalDataImpl;

namespace Rhino.Commons
{
    /// <summary>
    /// This class is key for handling local data, data that is private
    /// to the current context, be it the current thread, the current web
    /// request, etc.
    /// </summary>
    public static class Local
    {
        static readonly ILocalData current = new LocalData();
        static readonly object LocalDataHashtableKey = new object();
        private class LocalData : ILocalData
        {
            [ThreadStatic]
            static Hashtable thread_hashtable;

            private static Hashtable Local_Hashtable
            {
                get
                {
                    if (!RunningInWeb)
                    {
                        return thread_hashtable ??
                        (
                            thread_hashtable = new Hashtable()
                        );
                    }
                    Hashtable web_hashtable = HttpContext.Current.Items[LocalDataHashtableKey] as Hashtable;
                    if(web_hashtable==null)
                    {
                        HttpContext.Current.Items[LocalDataHashtableKey] = web_hashtable = new Hashtable();
                    }
                    return web_hashtable;
                }
            }

            public object this[object key]
            {
                get { return Local_Hashtable[key]; }
                set { Local_Hashtable[key] = value; }
            }

            public void Clear()
            {
                Local_Hashtable.Clear();
            }
        }

        /// <summary>
        ///     Gets the current data
        /// </summary>
        /// <value>The data.</value>
        public static ILocalData Data
        {
            get { return current; }
        }

        /// <summary>
        ///     Gets a value indicating whether running in the web context
        /// </summary>
        /// <value><c>true</c> if [running in web]; otherwise, <c>false</c>.</value>
        public static bool RunningInWeb
        {
            get { return HttpContext.Current != null; }
        }
    }
}

// Second part
using System;
using Rhino.Commons;

namespace IDL.Core.Util.NHibernate
{
    public class NhSqlAppender : IDisposable
    {
        private static string sql;
        private int usages = 1;

        public NhSqlAppender()
        {
        }

        public NhSqlAppender(string sqlToAppend)
        {
            sql = sqlToAppend;
        }

        public static NhSqlAppender Append(string sqlToAppend)
        {
            var currentAppender = Current;

            if (currentAppender == null)
            {
                Current = new NhSqlAppender(sqlToAppend);
                currentAppender = Current;
            }
            else
                currentAppender.IncrementUsages();

            return currentAppender;
        }

        public static NhSqlAppender Current
        {
            get { return Local.Data["NhSqlAppender"] as NhSqlAppender; }
            protected set { Local.Data["NhSqlAppender"] = value; }
        }

        public static string Sql
        {
            get { return (IsValid) ? sql : string.Empty; }
        }

        public static bool AppendSql
        {
            get { return IsValid; }
        }

        public void IncrementUsages()
        {
            ++usages;
        }

        public void DecrementUsages()
        {
            --usages;
        }

        private static bool IsValid
        {
            get { return (Current != null && !string.IsNullOrWhiteSpace(sql)); }
        }

        public void Dispose()
        {
            if (usages <= 1)
                Current = null;
            else
                DecrementUsages();
        }
    }
}

// Third part
namespace IDL.Core.Util.NHibernate
{
    public class NhQueryHint : NhSqlAppender
    {
        public static NhSqlAppender Recompile()
        {
            return Append("OPTION(RECOMPILE)");
        }
    }
}

// Fourth part
using System;
using IDL.Core.Util.NHibernate;
using NHibernate;

namespace IDL.Core.Configuration
{
    [Serializable]
    public class NhSqlAppenderInterceptor : EmptyInterceptor
    {
        public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
        {
            if (NhSqlAppender.AppendSql)
                return sql.Insert(sql.Length, (" " + NhSqlAppender.Sql));

            return base.OnPrepareStatement(sql);
        }
    }
}

// Fifth part
// You need to register the interceptor with NHibernate
// cfg = NHibernate.Cfg.Configuration
cfg.SetInterceptor(new NhSqlAppenderInterceptor());

// Finally, usage
using (NhQueryHint.Recompile())
    var results = IQueryable<T>.ToList();

您必须进行修改以适应您的环境。希望有帮助!


0
投票

@jvukovich 上面接受的答案对我帮助很大。我通过将重新编译提示的用法封装在扩展方法中来构建他的答案,如下所示。

// Extension Method

public static class NhQueryHintExtensions
{
    public static TReturn Recompile<T, TReturn>(this IQueryable<T> queryable, Func<IQueryable<T>, TReturn> toFunction)
    {
        using (NhQueryHint.Recompile())
        {
            return toFunction(queryable);
        }
    }
}

// Usage
var results = IQueryable<T>.Recompile(x => x.ToList());
© www.soinside.com 2019 - 2024. All rights reserved.