5

プロジェクトの 1 つ (および ASP.NET MVC アプリケーション) で Fluent NHibernate を使用しており、LINQ を使用してデータを照会しています (LINQ to NHibernate ライブラリを使用)。

罪のない人を守るためにオブジェクトの名前が変更されます。

次のクラス Foo、Bar、Baz、およびデータベース (MySQL) 内の適切なテーブルがあるとします。

Foo は、Fluent マッピングで定義されている Bar (テーブル "FooBar") と Baz (テーブル "FooBaz") の両方と多対多の関係にあります。そのため、クラス インターフェイスは次のように定義されます。

public class Foo {
    public virtual int id { get; set; }
    public virtual string name { get; set; }
    public virtual string email { get; set; }
    public virtual IList<Bar> bars { get; set; }
    public virtual IList<Baz> bazes { get; set; }
}

これはかなり標準的なクラスです。Foo オブジェクトがバーとベースのリストを持つことがわかります。

問題は、LINQ クエリを実行しようとしたときに発生します。

このような単純なクエリを実行すると、正常に動作します (where 句は重要ではありません)。

var foos = from foo in session.Linq<Foo>()
           where email.equals("foo@bar.com")
           select foo;

IList<Foo> listFoos = foos.ToList();

これにより、すべてのフィールド (id、name、email、bars、bazes) が入力された Foos のリストが返されます。log4net は、NHibernate がコレクションに対して個別のクエリを実行することを示しています。

一部のフィールドのみをロードしたい場合に問題が発生します。たとえば、クエリのバーのみをロードし、ベイズはロードしたくない場合があります。

このクエリはコンパイルされますが、実行時にエラーが発生します。

var foos = from foo in session.Linq<Foo>()
           where email.equals("foo@bar.com")
           select new Foo() 
           {
               id = foo.id,
               name = foo.name,
               email = foo.email,
               bars = foo.bars
           };

IList<Foo> listFoos = foos.ToList();

私が得るエラーは、範囲外の配列インデックスの行に沿ったものです。スタック トレースには、LINQ-NHibernate 側でのコレクション処理に関連するいくつかのメソッド名が示されていますが、それ以外は何も示されていません。log4net によって報告されたクエリには、バーに対するクエリの兆候は見られません。これは、バーを選択するためのクエリを実行する前にエラーが検出されたことを意味します。

他の誰かが以前にこの種の問題を抱えていましたか? どのように解決しましたか?アプリケーションで Web ページを開くたびにすべてのオブジェクトを選択する必要はありません。

ありがとうございました!

編集:リクエストされたスタックトレースは次のとおりです。

System.IndexOutOfRangeException: L'index se trouve en dehors des limites du tableau. (read: "Index is out of bounds for the array.")

[IndexOutOfRangeException: L'index se trouve en dehors des limites du tableau.]
   NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.InvokeMemberInitExpression(MemberInitExpression expression, Object[] args, Int32& argumentCount) +404
   NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.TransformTuple(Object[] tuple, String[] aliases) +150

[QueryException: could not instantiate: Foo]
   NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.TransformTuple(Object[] tuple, String[] aliases) +265
   NHibernate.Loader.Criteria.CriteriaLoader.GetResultColumnOrRow(Object[] row, IResultTransformer resultTransformer, IDataReader rs, ISessionImplementor session) +171
   NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies) +330
   NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +704
   NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +70
   NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +111
   NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) +18
   NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) +79
   NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) +407
   NHibernate.Impl.CriteriaImpl.List(IList results) +41
   NHibernate.Impl.CriteriaImpl.List() +35
   NHibernate.Linq.<GetEnumerator>d__0.MoveNext() +71
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +7665172
   System.Linq.Enumerable.ToList(IEnumerable`1 source) +61
   FooRepository.List(Int32 count) in C:\...\FooRepository.cs:38
   FooController.List() in C:\...\FooController.cs:30
   lambda_method(ExecutionScope , ControllerBase , Object[] ) +39
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +178
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +24
   System.Web.Mvc.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7() +52
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +254
   System.Web.Mvc.<>c__DisplayClassc.<InvokeActionMethodWithFilters>b__9() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399
   System.Web.Mvc.Controller.ExecuteCore() +126
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
   System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151
   System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57
   System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
4

4 に答える 4

6

いくつかの提案...

まず、NHibernate はデフォルトで遅延読み込みを行うため、試行しているより「効率的な」クエリを実行する必要さえない場合があります。

第 2 に、次のコードはサンプル コードとはまったく異なります。Foo のフィールドのサブセットを含む、miniFoos と呼ばれる匿名型のリストを作成します。しかし、最終的な効果は、あなたが試みているように見えるものと似ています. また、LINQ メソッド構文と呼ばれるものも使用します。

IList プロパティを持つ自分のアプリケーションのエンティティでこれをテストしましたが、動作します (ただし、現在イーガー ロードを使用していることに注意してください)。作業コードを切り取って貼り付け、例の名前を置き換えました。

        using( var session = sessionFactory.OpenSession() )
        {
            session.BeginTransaction();

            var foos =
                session.CreateCriteria(typeof(Foo))
                       .List<Foo>();

            var miniFoos = 
               foos.Select(f => new { f.email, f.bars })
                   .Where(f => f.email.Equals("foo@bar.com)
                   .ToList();

            session.Close();
         }
于 2010-01-05T17:47:18.193 に答える
2

私はすでにこれに答えようとしましたが、満足していません。

あなたの質問について考えれば考えるほど、私の経験では、NHibernate が独自に処理する独自のバージョンの遅延読み込みを実行しようとしているように思えます。

セッションを開いたままにしていなかったため、Eager Loadingに切り替えたことを(コメントから)知っています。その角度に焦点を当てた方が、長期的にはあなたにとってより役立つと思います.

私が誤解している場合は、質問を編集して、自分で処理する必要があると思う理由を説明できますか?

于 2010-01-06T17:15:17.627 に答える
1

コレクション全体ではなく、そのフィールドを投影することができました

   ... 
   Select(a => new Forum {
   Id = a.Id, 
   Name = a.Name, 
   CategoryName = a.Categories.Select(b => b.Name).First() 
   })

CategoryNameは、DBとのマッピングがない、フォーラムエンティティに提出された計算済みファイルです。

その結果、私は巨大なフォーラムエンティティの小さな予測とフィールドでの並べ替えの可能性を得ました。

それが誰かを助けることを願っています。

于 2012-10-29T08:51:09.633 に答える
0

結果トランスフォーマーと結果セット名を定義することで問題を解決できると思います。何らかの方法で生成される基準にアクセスできれば、匿名オブジェクトを回避できます。

問題は、プロパティ名と列名が同じではないことです。プロジェクション nhibernate/linq を使用して nhibernate を実行すると、列名とプロパティ名がチェックされません。したがって、クエリを実行する前に、条件の結果プロパティ(結果セットと呼ばれると思います)でそれらを自分で定義すると、機能するはずです。

それはとても簡単です、試してみてください

于 2010-01-06T13:08:33.373 に答える