ذاكرة التخزين المؤقت NHibernate من المستوى الثاني، استعلام مخصص، sqldialect

StackOverflow https://stackoverflow.com/questions/2461658

  •  20-09-2019
  •  | 
  •  

سؤال

حصلت على نسخة الجذع من NH وFNH.عندما أحاول إضافة ذاكرة تخزين مؤقت من المستوى الثاني، تنسى بعض أجزاء NHibernate أمر sqldialect المختار.


الترتيب الأولي:

var cfg = Fluently.Configure()
  .Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(connectionString)
    .DefaultSchema("dbo")
    .UseReflectionOptimizer()    
  .Mappings(m => ................);

الاستعلام المخصص المذنب:

var sql = @"with Foo(col1,col2,col3)
              as (select bla bla bla...)
            Select bla bla bla from Foo";

list = Session.CreateSQLQuery(sql)
  .AddEntity("fizz", typeof(Fizz))
  .SomethingUnimportant();

عندما أقوم بتغيير التكوين إلى:

var cfg = Fluently.Configure()
  .Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(connectionString)
    .DefaultSchema("dbo")
     .UseReflectionOptimizer()
     .Cache(c=>c
       .UseQueryCache()
         .ProviderClass<HashtableCacheProvider>())
       .ShowSql())
     .Mappings(m => ................);

الاستعلام يلقي خطأ (WITH تمت إضافة الجملة في mssql2008):

يجب أن يبدأ الاستعلام بـ "SELECT" أو "SELECT DISTINCT"

[استثناء غير مدعوم:يجب أن يبدأ الاستعلام بـ "SELECT" أو "SELECT DISTER"] mssql2005dialect.getLimitString (sqlstring QuerySqlString ، int32 إزاحة ، int32 last) +127 nhibernate.loader.loader.preparequerkomyCommand (queryparameters queryparameters ، boolean scrollement ، isessionimplementor). eryparameters queryparameters ، boolean returnproxies ) +352 nhibernate.loader.doqueryAndInitializenOnLazyCollections (جلسة IsessionImplementor ، QueryParameters QueryParameters ، Boolean Returnproxies) +114 nhibernate.loader.dolist


هل هناك أي أفكار حول ما يربك nhibernate بالضبط وكيفية إصلاحه؟


كود NHibernate المذنب (في NHibernate/Dialect/MsSql200Dialect.cs):

private static int GetAfterSelectInsertPoint(SqlString sql)
{
  if (sql.StartsWithCaseInsensitive("select distinct"))
  {
    return 15;
  }
  else if (sql.StartsWithCaseInsensitive("select"))
  {
    return 6;
  }
  throw new NotSupportedException
    ("The query should start with 'SELECT' or 'SELECT DISTINCT'");
  }
}

يبدو ذلك .SetMaxResults(123) يسبب هذا.لحسن الحظ، يمكنني إلغاء ربط هذا الاستعلام.

نأمل أن يحل هذا.

هل كانت مفيدة؟

المحلول

وكان لي مشكلة مشابهة (إزالة SetMaxResults ساعد أيضا ولكن كنت بحاجة الترحيل)، وتبين أن خاصية التكوين NHibernate التالية كان يسبب هذا الخطأ:

<property name="use_sql_comments">true</property>

وانها بالتأكيد خلل، لأن أسلوب GetAfterSelectInsertPoint لا يأخذ في الاعتبار ان تصريحات SQL يمكن إرفاق مسبقا إلى الاستعلام SQL.

ومجرد تعيين الخاصية use_sql_comments إلى false ويختفي المشكلة.

نصائح أخرى

وأنا إصلاح الأخطاء باستخدام محلول Alkampfer، ولكن أنا خلقت بلدي SQL اللهجة الخاصة بدلا من الترقيع مصدر NHibernate مباشرة:

public class Sql2008DialectWithBugFixes : MsSql2008Dialect
{
    public override SqlString GetLimitString(SqlString querySqlString, int offset, int last)
    {
        if (offset == 0)
        {
            return querySqlString.Insert(GetAfterSelectInsertPoint(querySqlString), " top " + last);
        }

        return base.GetLimitString(querySqlString, offset, last);
    }

    private static int GetAfterSelectInsertPoint(SqlString sql)
    {
        Int32 selectPosition;

        if ((selectPosition = sql.IndexOfCaseInsensitive("select distinct")) >= 0)
        {
            return selectPosition + 15; // "select distinct".Length;

        }
        if ((selectPosition = sql.IndexOfCaseInsensitive("select")) >= 0)
        {
            return selectPosition + 6; // "select".Length;
        }

        throw new NotSupportedException("The query should start with 'SELECT' or 'SELECT DISTINCT'");
    }
}
كان

وفقط نفس المشكلة باستخدام استعلام مشابهة الذي يحتوي على جملة WITH.

ومما يؤسف له، الاستعلام بلدي بملء الشبكة، مع الترحيل، لذلك يجب أن تبقي SetMaxResults.

وكان لي حل لإعادة كتابة باستخدام جدول مشتقة:

var sql = @"with Foo(col1,col2,col3)
              as (select x1, x2, x3 from x join y blabla)
            Select col1, col2, col3 from Foo
            join B on B.col1 = Foo.col1";

ويصبح

var sql = @"Select col1, col2, col3 from 
           (select x1 as col1, x2 as col2, x3 as col3 
            from x join y blabla) as Foo
           join B on B.col1 = Foo.col1";

وفقط للسماح NHibernate لإدراج "TOP س" سلسلة بعد "حدد" سلسلة (6 أحرف من البداية) ... لا تعليق: (

T

ويبدو أن هناك بعض الأخطاء غريب في روتين استخدامها للعثور على مكان في الاستعلام لإدراج بند TOP (GetAfterSelectInsertPoint) كما روى ساندور. يمكنك إصلاحه مباشرة في مصدر نيو هامبشاير (أنا في الواقع مصححة الإصدار 2.1 أنا باستخدام في المشروع، فيمكنك العثور على التفاصيل هنا ). حتى إذا كنت في حاجة على الاطلاق لتمكين التعليقات مع use_sql_comments يمكنك:)

لقد واجهت هذه المشكلة عند الترقية من 1.2 إلى 3.2 (أعرف، قفزة كبيرة، إيه؟).

كانت المشكلة في حالتي هي وجود مسافة بادئة أمام عبارة التحديد في hql، على سبيل المثال.سلسلة hql = "حدد"...

مع لغة SQL2005، يتعطل هذا مع "System.NotSupportedException:يجب أن يبدأ الاستعلام بالرسالة 'SELECT'...".

الحل هو

  1. إنشاء اختبار وحدة يفشل ، مطور جيد مدفوع بالاختبار يجب أن :)
  2. قم بإزالة المسافة البادئة من عبارة "حدد...".
  3. بناء وتشغيل اختبار الوحدة

وكما توقعت - unbounding حدد هو الحل المقبول

وSetMaxResults محذوفة ويعمل.

والتقينا هذه المشكلة عند الترقية إلى الإصدار 3.3 NHibernate، ولكن لسبب مختلف ... بيضاء. كان لدينا الكثير من سلاسل SQL التي يشبه هذا:

var sql = @"
select col1 from MyTable";

وأو:

var sql = @" select col1 from My Table";

وهذه أدت إلى "الاستعلام يجب أن تبدأ" SELECT 'أو' SELECT DISTINCT "الأخطاء لNHibernate لا تقليم السلسلة قبل التحقق من صحة ذلك.

ونحن خلقنا لهجة جديدة أن الديكورات السلسلة الأولى للالتفاف حول هذا:

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top