我正在尝试将“OPTION(RECOMPILE)”添加到我的一些 NHibernate 查询的末尾。我发现了以下帖子:
这描述了如何添加拦截器来附加 SQL。然而,他们使用 ICriteria,而我使用 LINQ 来查询我的数据。理想情况下,我希望能够这样说:
var query = session.Query<Foo>().OptionRecompile().ToList();
我想知道是否可以向 IQueryable 添加一个扩展方法,它将向查询中注入一些字符串,然后我可以在拦截器中检测到该字符串。这与上面文章中使用的方法类似,他们添加评论并进行检测。
欲了解更多信息。我之前处理过 LINQ 扩展,并且我知道您可以使用 HQL 生成器添加扩展属性/方法。但根据我的理解,这只能让我说:
var query = session.Query<Foo>().Where(f => f.Bar.OptionRecompile()).ToList();
这并不理想,看起来更像是一种黑客行为。如果有人可以提供帮助,我将不胜感激。谢谢
我最近也遇到了这个问题。我们想出了一个相当不错/强大的解决方案。重要的是它利用 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();
您必须进行修改以适应您的环境。希望有帮助!
@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());