2012-04-19 26 views
9

オブジェクトに対してグループ化を実行できますか?Entity Framework Groupオブジェクトまたは複合型での参照

public class MyObject { 
    public int SomeValue { get; set; } 
    public string SomeName { get; set; } 
    public string SomeOtherProperty { get; set; } 
} 

はもちろん、私は、次の操作を行うことができます::Item.MyObjectのような単純なオブジェクトである

from item in context.Items 
group item by item.MyObject 
select ... 

しかし

from item in context.Items 
group item by new { item.SomeValue, item.SomeName, item.SomeOtherProperty } 
select ... 

のプロパティの多くのオブジェクトによってグループ化する際に、このアプローチは面倒でエラーが起こりやすい。

上記のコードでは、「GroupByメソッドへの呼び出しのキーセレクター型が、基礎となるストアプロバイダーでは比較できません」というNotSupportedExceptionが発生します。 EqualsとGetHashcodeをオーバーライドしても効果はありません。本当の問題は、エンティティフレームワークがSQLを表現する方法を知らないということですね。

+0

EFモデルの「MyObject」部分ですか?私はMyObject(MyObject:Itemはn:1)のナビゲーションプロパティで同様のことをすることができます。生成されたSQLは恐ろしいですが、少なくとも動作します。 –

+0

実際にはComplexTypeです。つまり、EFはオブジェクトタイプを知っています。すべてのプロパティが実際に同じテーブルに存在するため、ナビゲーションプロパティを使用していた場合よりも、結果として得られるSQLの方がはるかにクリーンであることが期待できます( – mindlessgoods

答えて

7

苦いことに、あなたはそれをすることができません。 ComplexTypeは有望に見え、素敵な "列のグループ"と思われますが、EFチームは完全に他の用途に使用するように設計しています。

私の知る限りでは、「明らかに私は以下を行うことができます:」が可能な唯一の方法です。グループ化はサブ列ごとに定義するか、データベースが比較する方法を知っているいくつかの型に射影するだけです。

コアの問題は、それは一種の、実体の別のタイプであるEFチームはありませんあなたは多くのフィールドを使用してエンティティを整理することができ、列のグループとしてのComplexType を見ていることですが、彼らのために、一時的なもの。 ComplexTypeは、通常の既存のテーブル/クラスにマッピングできない5つの列の結果セットを返すストアドプロシージャ(またはテーブルを返す関数)から返されるオブジェクトを表すためのものです。たとえば、50の列/フィールドを含むテーブル/クラスCustomerがあり、そのほとんどはnullではなく、機密データを表しているとします。顧客のIDを取得し、{名前、住所、連絡先電話番号、靴サイズ}を返すストアドプロシージャを作成します。明らかに、このようにトリミングされた結果がセットされていれば、でないフィールドがたくさんあるCustomerクラスにデコード/マップすることはできません。では、EFの結果セットをどのように表現していますか?

最初の選択肢は、単にEFを無視してデータベースと直接話し合い、手作業で行/列を読み取り/変換/展開することです。さて、SqlClientはわかっています。

第2のオプションは、名前、アドレス、連絡先電話番号、靴サイズの列だけを含むスタブテーブル/ビュー(CustomerViewなど)をEFで定義し、ストアドプロシージャの結果セットをマップすることですそれに。それはうまくいくはずですが、あなたが事故でEFモデルからデータベースを生成すると、余分な未使用テーブルも得られます。

レスキューの3番目のオプションはComplexTypeです。シャドーテーブルやビューを作成するのではなく、が決して独自のテーブルにマップされず、PrimaryKeyは決してと定義されず、EFはあなたの便宜のために他のデータオブジェクトのようなクラスにマップしてください。さて、このような型を持つと、プロシージャから返すことができ、きれいに型付けされたオブジェクトとして取得することができます。プロシージャのパラメータなどとして渡すことができます。独自のテーブルマッピングはなく、プライマリキーもありません。それはアイデンティティを持っています。

このようなデータ型をプロシージャから返すのはなぜですか?たぶん、プロシージャが処理またはいくつかのデータを生成しました。をいくつかのテーブルに格納します。あなたは通常のエンティティ全体を定義していないので、物は単なる 'データパック'なので、おそらくその結果値を他のデータとともにそのテーブルに書き込むことになります。これは、EFがComplexTypeをテーブルのいくつかのカラムにマッピングすることを可能にする理由です。プロシージャからその一時的な結果オブジェクトを取得した後で、どこかに書きたい場合、カラムごとに手動で行う必要はありません顧客の「名前、住所、連絡先電話番号、靴のサイズ」の列にマップするだけです。

最も重要な点は、データベースサーバーがそのようなComplexTypeが存在することを知らないことです。私が言ったように、それはアイデンティティがなかった。あなたはその後、

aset.Where(item => item.complexProperty == complexValue) 

のようなLINQクエリを実行しようとすると、complexValueは、このようにPK NO、これEFはどのようにかどうかをチェックするために、完全にNO IDEAを持っていない、任意のテーブルにマップされていないCLRオブジェクトは、あるNOのアイデンティティを持っていません「左手オブジェクト」は「右手オブジェクト」と同じです。いくつかのアイデンティティーが定義されていれば、サーバー側でPKをチェックするか、クライアント側でオブジェクト参照の比較を行うことができますが、ここでは失敗します。

これは、EFに欠けているもう一つの気が利いた便利な機能だと私は全く同意します。私は、EFチームがComplexTypesを列単位で比較するのは非常に簡単だと信じていますが、そうではありませんでした。彼らは単純にComplexTypesをテーブルの整理に使用できるとは考えていませんでした。彼らは、ストアドプロシージャとストアドプロシージャと関数から継承される一時的なデータパックであることを意味しています。

+0

サイドノート:なぜなら、複雑なタイプのどこでフィルタリングしようとしたときに、私はちょうどそれに直面したからです。グループ分けは同様に異なりますが、それは「問題を比較する方法を知らない」という問題に終わります。もし誰かが何らかの回避策やEF拡張を知っていれば、私はそれについても知っていれば幸いです。今のところ、「申し訳ありませんが、これはまだEF5にはないかもしれない」という記事しか見つかりませんでした。 – quetzalcoatl

+0

詳細な回答ありがとうございます。これは将来のバージョンで見られる素晴らしい機能です。 – mindlessgoods

関連する問題