NHibernate LINQ添加查询提示

时间:2015-09-25 08:55:19

标签: linq nhibernate linq-to-nhibernate

我试图添加" OPTION(RECOMPILE)"到我的一些NHibernate查询结束。我发现了以下帖子:

http://www.codewrecks.com/blog/index.php/2011/07/23/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();

这不是理想的,似乎更像是一种黑客攻击。如果有人可以提供帮助,我会很感激。感谢

1 个答案:

答案 0 :(得分:2)

我最近也遇到过这个问题。我们提出了一个相当不错/强大的解决方案。重要的是它利用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();

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