left nhibernate fluent-nhibernate criteria

left - nhibernate session createquery



¿Cómo se agrega NOLOCK con nHibernate? (5)

¿Cómo se agrega NOLOCK cuando se utiliza nhibernate? (consulta de criterios)


Si va a utilizarlo en muchas de sus consultas, puede configurarlo como predeterminado a través de la propiedad de configuración connection.isolation .

<property name="connection.isolation">ReadUncommitted</property>

Consulte la documentación de esta propiedad .



Esto no agrega NOLOCK a sus consultas que puedo ver, pero debe proporcionar la misma funcionalidad, que es realizar lecturas sucias solo dentro de una transacción.

Session.BeginTransaction(IsolationLevel.ReadUncommitted);

Utilicé Sql Profiler para ver lo que haría el comando anterior pero no cambió nada sobre la consulta ni les agregué NOLOCK (nhibernate usa sp_executesql para la mayoría de mis consultas). Corrí con él de todos modos, y parece que todos los bloqueos se han ido. Nuestro software ha estado funcionando de esta manera durante 3 días sin interbloqueos. Antes de este cambio, normalmente podía reproducir los bloqueos en 15 minutos. No estoy 100% convencido de que esto lo solucionó, pero después de otras semanas de pruebas, sabré más.

Esto también ha funcionado para otros: http://quomon.com/NHibernate-deadlock-problem-q43633.aspx


Puedes resolverlo usando Interceptor.

var session = SessionFactory.OpenSession(new NoLockInterceptor());

Aquí está la implementación para la clase NoLockInterceptor. Básicamente, la clase NoLockInterceptor insertará la sugerencia "WITH (NOLOCK)" después de cada nombre de tabla en la consulta de selección, generada por nHibernate.

public class NoLockInterceptor : EmptyInterceptor { public override SqlString OnPrepareStatement(SqlString sql) { //var log = new StringBuilder(); //log.Append(sql.ToString()); //log.AppendLine(); // Modify the sql to add hints if (sql.StartsWithCaseInsensitive("select")) { var parts = sql.ToString().Split().ToList(); var fromItem = parts.FirstOrDefault(p => p.Trim().Equals("from", StringComparison.OrdinalIgnoreCase)); int fromIndex = fromItem != null ? parts.IndexOf(fromItem) : -1; var whereItem = parts.FirstOrDefault(p => p.Trim().Equals("where", StringComparison.OrdinalIgnoreCase)); int whereIndex = whereItem != null ? parts.IndexOf(whereItem) : parts.Count; if (fromIndex == -1) return sql; parts.Insert(parts.IndexOf(fromItem) + 3, "WITH (NOLOCK)"); for (int i = fromIndex; i < whereIndex; i++) { if (parts[i - 1].Equals(",")) { parts.Insert(i + 3, "WITH (NOLOCK)"); i += 3; } if (parts[i].Trim().Equals("on", StringComparison.OrdinalIgnoreCase)) { parts[i] = "WITH (NOLOCK) on"; } } // MUST use SqlString.Parse() method instead of new SqlString() sql = SqlString.Parse(string.Join(" ", parts)); } //log.Append(sql); return sql; } }


Explicaré cómo hacerlo para que pueda agregar NOLOCK (o cualquier otra sugerencia de consulta), mientras sigue usando ICriteria o HQL, y sin tener que conocer sus consultas en las asignaciones o la configuración de fábrica de la sesión.

Escribí esto para NHibernate 2.1. Hay varias advertencias importantes con respecto a esto, principalmente debido a errores en NHibernate cuando se activa "use_sql_comments" (ver a continuación). No estoy seguro si estos errores han sido arreglados en NH 3, pero pruébalo. ACTUALIZACIÓN: los errores no se han corregido a partir de NH 3.3. La técnica y las soluciones que describo aquí todavía funcionan.

En primer lugar, crea un interceptor, como este:

[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); } }

Luego crea algunos buenos métodos de extensión en alguna parte:

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)); } }

Luego, dile a NHibernate que use tu interceptor:

config.SetInterceptor(new QueryHintInterceptor());

Finalmente, habilite la propiedad use_sql_comments en su configuración de NHibernate.

¡Y tu estas listo! Ahora puede agregar sugerencias de nolock como esta:

var criteria = Session.CreateCriteria<Foo>() .QueryHintNoLock("tableFoo") .List<Foo>();

Basé este trabajo en la técnica descrita aquí: http://www.codewrecks.com/blog/index.php/2011/07/23/use-sql-server-query-hints-with-nhibernate-hql-and- icriteria /

NHibernate muestra errores de bloqueo:

En primer lugar, hay un error con NHibernate que deberá corregir. (Puede corregir este error reparando la fuente NHibernate directamente, o haciendo lo que hice y creando su propio dialecto que repara el problema).

En segundo lugar, hay otro error que parece ocurrir cuando haces una búsqueda paginada, en cualquier página después de la primera página, y estás usando proyecciones. El sql generado por NHibernate es completamente incorrecto en torno a la cláusula "OVER". En esta etapa, no sé cómo solucionar este error, pero estoy trabajando en ello. ACTUALIZACIÓN: he detallado cómo solucionar este error aquí . Al igual que el otro error, este también se puede solucionar reparando el código fuente de NHibernate o creando su propia clase Dialect.