質問

Linq to NHibernate クエリで複数のフィールドで順序付けするのに問題があります。何が問題なのか、あるいは回避策があるのか​​知っている人はいますか?

コード:

IQueryable<AgendaItem> items = _agendaRepository.GetAgendaItems(location)
   .Where(item => item.Minutes.Contains(query) || item.Description.Contains(query));

int total = items.Count();

var results = items
   .OrderBy(item => item.Agenda.Date)
   .ThenBy(item => item.OutcomeType)
   .ThenBy(item => item.OutcomeNumber)
   .Skip((page - 1)*pageSize)
   .Take(pageSize)
   .ToArray();

return new SearchResult(query, total, results);

ThenBy を複数の OrderBy 呼び出しに置き換えてみました。同じ結果です。2 つの thenBy 呼び出しをコメントアウトすると、このメソッドはうまく機能します。

受信したエラー:

    [SqlException (0x80131904): Invalid column name '__hibernate_sort_expr_0____hibernate_sort_expr_1__'.
    Invalid column name '__hibernate_sort_expr_0____hibernate_sort_expr_1__'.]
       System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +1948826
       System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +4844747
       System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +194
       System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2392

    [ADOException: could not execute query
    [ SELECT this_.Id as Id5_2_, this_.AgendaId as AgendaId5_2_, this_.Description as Descript3_5_2_, this_.OutcomeType as OutcomeT4_5_2_, this_.OutcomeNumber as OutcomeN5_5_2_, this_.Minutes as Minutes5_2_, agenda1_.Id as Id2_0_, agenda1_.LocationId as LocationId2_0_, agenda1_.Date as Date2_0_, location2_.Id as Id7_1_, location2_.Name as Name7_1_ FROM AgendaItem this_ left outer join Agenda agenda1_ on this_.AgendaId=agenda1_.Id left outer join Location location2_ on agenda1_.LocationId=location2_.Id WHERE location2_.Id = ? and (this_.Minutes like ? or this_.Description like ?) ORDER BY agenda1_.Date asc, this_.OutcomeType asc, this_.OutcomeNumber asc ]
    Positional parameters:  #0>1 #0>%Core% #0>%Core%
    [SQL: SELECT this_.Id as Id5_2_, this_.AgendaId as AgendaId5_2_, this_.Description as Descript3_5_2_, this_.OutcomeType as OutcomeT4_5_2_, this_.OutcomeNumber as OutcomeN5_5_2_, this_.Minutes as Minutes5_2_, agenda1_.Id as Id2_0_, agenda1_.LocationId as LocationId2_0_, agenda1_.Date as Date2_0_, location2_.Id as Id7_1_, location2_.Name as Name7_1_ FROM AgendaItem this_ left outer join Agenda agenda1_ on this_.AgendaId=agenda1_.Id left outer join Location location2_ on agenda1_.LocationId=location2_.Id WHERE location2_.Id = ? and (this_.Minutes like ? or this_.Description like ?) ORDER BY agenda1_.Date asc, this_.OutcomeType asc, this_.OutcomeNumber asc]]
       NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +258
       NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) +18
       NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) +87
       NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) +342
       NHibernate.Impl.CriteriaImpl.List(IList results) +41
       NHibernate.Impl.CriteriaImpl.List() +35
       NHibernate.Linq.CriteriaResultReader`1.List() in C:\home\dev\tools\NHibernate\NHibernateContribSrc\src\NHibernate.Linq\src\NHibernate.Linq\CriteriaResultReader.cs:22
       NHibernate.Linq.d__0.MoveNext() in C:\home\dev\tools\NHibernate\NHibernateContribSrc\src\NHibernate.Linq\src\NHibernate.Linq\CriteriaResultReader.cs:27
役に立ちましたか?

解決

これは、Linq to NHybernate のバグのように思えます。考えられる回避策の 1 つは、並べ替える前に配列に変換することです。潜在的に大きな欠点は、列挙する前に Skip() と Take() を使用して結果を制限できないことです。そのため、これでは十分ではない可能性があります。

var results = items
   .ToArray()
   .OrderBy(item => item.Agenda.Date)
   .ThenBy(item => item.OutcomeType)
   .ThenBy(item => item.OutcomeNumber)
   .Skip((page - 1)*pageSize)
   .Take(pageSize)

他のヒント

それが違いを生むとは思いませんが、linqを次のように実行するとどうなりますか:

(アイテムの順序 i.prop1、i.prop2、i.prop3 の i から).Skip(...).Take(...).ToArray();

結果セットが比較的小さい場合は、最初に配列に変換することが許容できる解決策になる可能性があります。ただし、SQL Server にその仕事をさせたい場合は、次のようにした方がよいでしょう。

var results = items
   .OrderBy(item => item.Agenda.Date).Asc
   .ThenBy(item => item.OutcomeType).Asc
   .ThenBy(item => item.OutcomeNumber).Asc
   .Skip((page - 1)*pageSize)
   .Take(pageSize)
   .ToArray();

Linq の NHibernate 方言で OrderBy または OrderByAlias メソッドを使用するときは、必ず後で Asc または Desc 修飾子を追加する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top