2017-10-04 3 views
0

考えると2つのクラスが最初のEFでコードを生成したエンティティへのLINQでのIQueryable上のSQLに変換しました財産合計は親子関係で、

しかし、私はそのようにこれを行う、次に行う場合

var list = ctx.Parents 
        .Where(p => p.Total > 1000) 
        .Select(p => new { 
         p.Id, 
         p.Total, 
         Count = p.Children.Count }); 
foreach(var item in list){ 
     Console.WriteLine($"Id: {item.} ..."); 
} 

私は型「System.NotSupportedException」が

未処理の例外がEntityFramework.SqlServer.dll

で発生したというエラーを得た

追加情報:指定されたタイプのメンバー「合計」にLINQでサポートされていません。エンティティ。初期化子、エンティティメンバー、エンティティナビゲーションプロパティのみがサポートされています。

私の意見では、EFが質問を生成するのは難しいことではありませんが、SUM(UnitPrice * Amount) as Total私はそれを動作させることができません。

それだけのコードでこの計算を行うことが許容されるべきである一方で、私はすでに

public static Expression<Func<Parent, decimal>> GetTotal() 
    { 
     return p=> p.Children.Sum(line => line.ItemQty * line.UnitPrice); 
    } 

のような静的な表現でそれを試してみました。この例を使用して、IQueryableを使用する方法の詳細を知りたいとします。

Aリトル大成功

親の次の静的プロパティに

public static Expression<Func<Parent, decimal?>> Total => 
     p=> (from c in p.Childeren 
      select c.UnitPrice * c.ItemQty).Sum(); 

を与えられ、そして、私はすべての合計を含むリストを持って、私がいることがわかり

var list = ctx.Parents.Select(Parent.Total); 

をやってEFが次のクエリを生成しました

SELECT 
    (SELECT 
     SUM([Filter1].[A1]) AS [A1] 
     FROM (SELECT 
      [Extent2].[UnitPrice] * CAST([Extent2].[Amount] AS decimal(19,0)) AS [A1] 
      FROM [dbo].[Child] AS [Extent2] 
      WHERE [Extent1].[Id] = [Extent2].[ParentId] 
     ) AS [Filter1]) AS [C1] 
    FROM [dbo].[Parent] AS [Extent1] 

したがって、実際にはEFはSum()メソッドをSQLに変換できます。今はWhere()で使用するだけです。

答えて

1

計算されたプロパティは、クラスでのみ認識され、データベースでは認識されません。これらの計算されたプロパティにアクセスする前に、オブジェクトを(クラスに)インスタンス化する必要があります。

var list = ctx.Parents 
       .Include(p => p.Children) //Children will be populated upon instantiation 
       .Where(p => p.Total > 1000) 
       .ToList() //This instantiates your data into objects 
       .Select(p => new { 
        p.Id, 
        p.Total, 
        Count = p.Children.Count }); 

var list = ctx.Parents 
       .Where(p => p.Total > 1000) 
       .ToList() //This instantiates your data into objects 
       .Select(p => new { 
        p.Id, 
        p.Total, 
        Count = p.Children.Count }); 

これは、あなたが遅延ローディングか持っているかどうかに応じて、ステートメントを含める必要があります。

それは難しいこの作業を取得することはありません

私の意見では、EFがクエリを生成するのは難しくありません。SUM(UnitPrice * Amount) as Total私はそれを動作させることができません。

あなたが言及している以上に多くのことがあります。

SUM何のですか? 現在のの結果(Parentsのテーブル)ではなく、というグループのテーブルの計算の合計を計算します。これは、これまで作業していたデータセットとはまったく異なるデータセットです。

これはEFがあなたがしたいことをしない理由です。クエリの一部であるSELECTを決定しようとしていますが、より複雑なクエリ本体が必要です。子どもと親を一緒に結合して子どもの計算を行い、それらの結果を単一の値に合計します。

SQLクエリを自分で作成しようとすると、多くの場合、は、SUM(UnitPrice * Amount) as Totalよりも複雑です。

+0

ありがとうございます。私たちは実際にEFが9秒を要するパフォーマンス問題(これより複雑なシナリオ)を手作業で300ミリ秒以下で解決しています。私はEFの機能を調査しています。私はSQLクエリを手作業で作成し、DB内のBusiness Logicを複製することに戻りたいからです。 –

+0

@StijnVanAntwerpen EFは追加レイヤーです。せいぜい、SQLクエリーの手作業と比較して、同等のパフォーマンス(またはわずかなパフォーマンス)しか得られません。 EFはC#から暗黙的にSQLに変換できるものによって制限されています。 – Flater

+0

まあ、私はEFはSQLに(もちろん、それはまだ魔法を使用していない)C#を変換することが制限されて知っている。私はSum()のようなものがサポートされていることを期待していました...実際にDB(VW_ParentWithTotal)のビューを定義すると、EFからモデルを生成できます。オーバーヘッドは無視できます。しかし、私はそのステップを排除しようとしています。 (VW_ParentWithTotalにはBLが既に存在しているので、C#にはすでに存在しています) –