如何使用nHibernate添加NOLOCK?
如何在使用nhibernate时添加NOLOCK? (标准查询)
SetLockMode(LockMode.None)
或connection.isolation ReadUncomitted
不附加NOLOCK
到您的查询。
Ayende在他的博客上进入正确的答案:
如果您使用<sql-query>
,则可以执行以下操作:
<sql-query name="PeopleByName">
<return alias="person"
class="Person"/>
SELECT {person.*}
FROM People {person} WITH(nolock)
WHERE {person}.Name LIKE :name
</sql-query>
请注意附加到FROM
子句的WTIH(nolock)
。
我将解释如何做到这一点,以便您可以添加NOLOCK(或任何其他查询提示),同时仍使用ICriteria或HQL,而无需将查询知识保存到映射或会话工厂配置中。
我为NHibernate 2.1写了这个。 有一些主要的注意事项,主要是由于NHibernate中的“use_sql_comments”打开时出现错误(见下文)。 我不确定这些错误是否已在NH 3中得到修复,但请尝试一下。 更新:错误没有被修复为NH 3.3。 我在这里描述的技术和解决方法仍然有效。
首先,创建一个拦截器,如下所示:
[Serializable]
public class QueryHintInterceptor : EmptyInterceptor
{
internal const string QUERY_HINT_NOLOCK_COMMENT = "queryhint-nolock: ";
/// <summary>
/// Gets a comment to add to a sql query to tell this interceptor to add 'OPTION (TABLE HINT(table_alias, INDEX = index_name))' to the query.
/// </summary>
internal static string GetQueryHintNoLock(string tableName)
{
return QUERY_HINT_NOLOCK_COMMENT + tableName;
}
public override SqlString OnPrepareStatement(SqlString sql)
{
if (sql.ToString().Contains(QUERY_HINT_NOLOCK_COMMENT))
{
sql = ApplyQueryHintNoLock(sql, sql.ToString());
}
return base.OnPrepareStatement(sql);
}
private static SqlString ApplyQueryHintNoLock(SqlString sql, string sqlString)
{
var indexOfTableName = sqlString.IndexOf(QUERY_HINT_NOLOCK_COMMENT) + QUERY_HINT_NOLOCK_COMMENT.Length;
if (indexOfTableName < 0)
throw new InvalidOperationException(
"Query hint comment should contain name of table, like this: '/* queryhint-nolock: tableName */'");
var indexOfTableNameEnd = sqlString.IndexOf(" ", indexOfTableName + 1);
if (indexOfTableNameEnd < 0)
throw new InvalidOperationException(
"Query hint comment should contain name of table, like this: '/* queryhint-nlock: tableName */'");
var tableName = sqlString.Substring(indexOfTableName, indexOfTableNameEnd - indexOfTableName).Trim();
var regex = new Regex(@"{0}s(w+)".F(tableName));
var aliasMatches = regex.Matches(sqlString, indexOfTableNameEnd);
if (aliasMatches.Count == 0)
throw new InvalidOperationException("Could not find aliases for table with name: " + tableName);
var q = 0;
foreach (Match aliasMatch in aliasMatches)
{
var alias = aliasMatch.Groups[1].Value;
var aliasIndex = aliasMatch.Groups[1].Index + q + alias.Length;
sql = sql.Insert(aliasIndex, " WITH (NOLOCK)");
q += " WITH (NOLOCK)".Length;
}
return sql;
}
private static SqlString InsertOption(SqlString sql, string option)
{
// The original code used just "sql.Length". I found that the end of the sql string actually contains new lines and a semi colon.
// Might need to change in future versions of NHibernate.
var regex = new Regex(@"[^;s]", RegexOptions.RightToLeft);
var insertAt = regex.Match(sql.ToString()).Index + 1;
return sql.Insert(insertAt, option);
}
}
然后在某处创建一些漂亮的扩展方法:
public static class NHibernateQueryExtensions
{
public static IQuery QueryHintNoLock(this IQuery query, string tableName)
{
return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName));
}
public static ICriteria QueryHintNoLock(this ICriteria query, string tableName)
{
return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName));
}
}
接下来,告诉NHibernate使用你的拦截器:
config.SetInterceptor(new QueryHintInterceptor());
最后,在NHibernate配置中启用use_sql_comments属性。
你完成了! 现在你可以添加像这样的nolock提示:
var criteria = Session.CreateCriteria<Foo>()
.QueryHintNoLock("tableFoo")
.List<Foo>();
我将这项工作基于这里描述的技术:http://www.codewrecks.com/blog/index.php/2011/07/23/use-sql-server-query-hints-with-nhibernate-hql-and-的ICriteria /
NHibernate展示Bug:
首先,NHibernate存在这个bug,你需要修复。 (你可以通过直接修复NHibernate的源代码来修复这个bug,或者通过做我做的和创建你自己的方言来修复问题)。
其次,当您在第一页之后的任何页面上执行分页查询,并且您正在使用投影时,似乎会出现另一个错误。 由NHibernate生成的SQL在“OVER”子句周围是完全错误的。 在这个阶段,我不知道如何解决这个错误,但我正在努力。 更新:我已经详细说明了如何解决这个bug。 像其他bug一样,这个也可以通过修复NHibernate源代码或创建自己的Dialect类来修复。
如果您要在很多查询中使用它,可以通过配置属性connection.isolation
将其设置为默认值。
<property name="connection.isolation">ReadUncommitted</property>
查看该属性的文档。
链接地址: http://www.djcxy.com/p/32851.html