2017-02-03 7 views
0

"クライアント"というエンティティと、 "カード"というエンティティを持っています。EF6を使用して相対エンティティのカウントを得る方法

クライアントは、多くの場合、カードを持つ場合があります。

マイクライアントエンティティは次のようになります。

public class Client{ 
    public virtual ICollection<Card> Cards {get; set;} 
} 

は今、私はWPFのDataGrid内クライアントデータを表示したい、と私はカードを取得したいデータをカウントするので、私が追加

public class Client{ 
    public virtual ICollection<Card> Cards {get; set;} 

    public int CardCount 
    { 
     return Cards.Count; 
    } 
} 

そして、私はデータwを照会:このようクライアントエンティティへのプロパティ私は、アプリケーションを実行すると、LINQのとバインドが

var query = from n in db.Clients select n; 

を表示するi番目、私はちょうどreturn Cards.Count;ライン上の例外を得ました。

System.ObjectDisposedException 
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. 

それでは、どのように私は正しくカードはを数える得ることができますか?

答えて

1

ここで他の回答のショーよりも方法簡単な方法があります。

var client = db.Clients.FirstOrDefault(c=> c.Id = someid); //get a client 
if (client != null) 
{ 
    cardCount = client.Cards.Count; 
} 

などの解決策では、N + 1の選択問題という問題が発生することにご注意ください。興味があればそれをお読みください。

正確なクライアントに興味があるだけでなく、Nのクライアントを表示したいので、1つのクエリを実行する必要がありますちょうどクライアントを取得します。次に、FirstOrDefaultの処理を行うことで、実際にはClientレコードごとにデータベースへの1つの余分なDBラウンドトリップが行われ、結果として追加のN * 1 = Nラウンドトリップが発生します。つまり、関連するデータなしでClientsを照会するだけであれば、好きなクライアントレコードを1つのクエリで得ることができます。しかし、それぞれに関連するデータを1つずつフェッチすることで、dbラウンドトリップが多すぎます。

ここでは、結合と投影を使用してこの問題を解決する方法を示します。 1つのDBアクセスで必要なすべてのデータを得ることができます。

using (var context = GetDbContext()) 
{ 
    return context.Clients.Select(cli => new YourViewModel 
    { 
     Name = cli.FullName, 
     // Other prop setters go here 
     CardCount = cli.Cards.Count 
    }).Skip((page - 1) * pageSize).Take(pageSize).ToList(); 
} 

あなたはおそらく、違いは何ですか?ここでは、マテリアライズされたオブジェクトで作業しているわけではありません。他の人がここで呼び出すのはDbContextです。適切なLINQ演算子を適用することで(これは、DbContextだけでなく、IQueryableでも動作することに注意してください(すでにメモリ内のコレクションにAsQueryable()を呼び出した場合はそうではありません))、LINQ to Entitiesは適切なSQLを使用してテーブルを結合し、結果を投影し、必要なすべてのデータを一度に取得します。 LYQ to Entitiesはcli.Cards.Countを適切なSQL Countステートメントに変換することができることに注意してください。

+0

そこに問題があります。クライアントエンティティインスタンスをデータグリッドに直接バインドします。クライアントエンティティにプロパティがない場合は、どのようにCardsCount列データを表示しますか? –

+0

シンプルです。問合せされた内容や方法を適切に制御できるように、データに適切なラッパーを実装する必要があります。これは、パフォーマンスを適切に制御する唯一の方法です。しかし、自分で小道具にアクセスする必要がなく、結果に関係する唯一のものが 'DataGrid'であれば、匿名型を使用して結果を*非永続的コレクションとして返すことができます'DataGrid'もそれにバインドできます。 –

+0

私はそれを試して、例外が発生しました:メソッド 'スキップ'は、LINQ to Entitiesのソートされた入力に対してのみサポートされています。 –

-1

取得されたクエリを具体化しないと、ObjectDisposedExceptionが返されます。次のケースでは、メソッドを終了する前ではなく、初めてGetNonMaterializedからリストにアクセスしたときにのみクエリが実行されます。このdbの事実は、範囲の喪失により処分されます。

public IEnumerable<Client> GetNonMaterialized() 
{ 
    return from n in db.Clients select n; 
} 

以下の場合、メソッドを終了する前にクエリが実行されます。

public IEnumerable<Client> GetMaterialized() 
{ 
    return (from n in db.Clients select n).ToList(); 
} 

は常にクエリがObjectContextの範囲を出before実行されていることを確認してください。

クエリが実行されているかどうか、EFのenalbe Loggingがいつ実行されているかを知りたい場合。

How can I turn off Entity Framework 6.1 logging?

+0

どこにGetMaterializedメソッドを配置する必要がありますか?どうすれば使えますか?私はWPFの初心者ですので、もっと詳しく教えてください。ありがとう〜 –

+0

これは動作しません。 'ToList'を呼び出すことによって、非遅延プロパティを強制的に挿入するだけです。関連して遅延ロードされたエンティティまたはそれらのコレクションはロードされません。 2つのコードフラグメントの唯一の違いは、最初のものではコンテキストがアクセス前に破棄され、2番目のものでは少なくとも基本プロパティを取得できれば、非遅延プロペラをフェッチすることさえできないということです。 –

0

あなたはこのようにエンティティをロードせずにカウントを取得することができます

using (var context = new MyContext()) 
{ 
    var client = context.Client.Find(clientId); 

    // Count how many cards the client has 
    var cardsCount = context.Entry(client) 
         .Collection(b => b.Cards) 
         .Query() 
         .Count(); 
} 

詳しい情報on MSDN pageを。

+0

彼は 'DataGrid'を使用しているので、私は彼が望むと思います複数のクライアントの詳細を表示すると、選択されたn + 1の問題が発生します。 –

+0

これはビューモデルで使用でき、そこにカードの数が表示されます。私はエンティティ自体にそのプロパティを持つのは良い設計だとは思わない。 –

+0

それをviewModelに入れるのは良い考えでもありません。 viewModelには、*任意の*ロジックが定義で含まれるべきではありません。そして、あなたがこれをどこで行っても、データベースへの複数回のラウンドトリップを避けることができる唯一の場所は、他のデータと一緒にこの値を選択する場合です。エンティティの内側にもビューモデルにも配置されないので、選択したn + 1を防ぐことができます。 –

関連する問題