12

500列を超える非常に大きなテーブルがあります(誰かがそうしていることは知っています!)

これらの列の多くは、実際には他のテーブルへの外部キーです。

また、関連するテーブルのいくつかを熱心にロードする必要があります。

Linq toSQLまたはDynamicLinqで、データベースから取得する列を指定する方法はありますか?生成されたSQLステートメントに実際にこの影響を与えるlinqステートメントを探しています。

SELECT Id, Name FROM Book

EFによって生成された通常のクエリを実行すると、SQL Serverは、クエリ内で選択できる列の最大数に達したというエラーをスローします!!!

どんな助けでも大歓迎です!


はい、まさにその通りです。テーブルには500列があり、ツールが自動的に第1レベルのリレーションを自動的にロードする自己参照を行っているため、クエリできる列数のSQL制限に達します。

IDや名前(UIでユーザーにレコードを表示するために使用される)など、関連するエンティティの限定された列のみをロードするように設定できることを望んでいました。

もう1つのオプションは、どのFK列を熱心にロードするかを制御することだと思います。ただし、これは、常にロードしたくないバイナリまたはntext列を持つテーブルでは依然として問題です。

コードファーストの同じテーブルに複数のモデル(エンティティ)をフックする方法はありますか?私たちはこれをやってみましたが、努力は惨めに失敗したと思います。

4

2 に答える 2

19

はい、射影を使用して列のサブセットのみを返すことができます。

var result = from x in context.LargeTable
             select new { x.Id, x.Name };

問題:投影と積極的な読み込みが一緒に機能しません。プロジェクションまたはカスタム結合の使用を開始すると、クエリの形状が変更され、使用できなくなりますInclude(EFはそれを無視します)。このようなシナリオでの唯一の方法は、予測される結果セットにリレーションを手動で含めることです。

var result = from x in context.LargeTable
             select new {
                 Id = x.Id,
                 Name = x.Name,
                 // You can filter or project relations as well
                 RelatedEnitites = x.SomeRelation.Where(...) 
             };

特定のタイプに投影することもできますが、その特定のタイプをマップしてはなりません(たとえばLargeTable、私のサンプルからエンティティにプロジェクトすることはできません)。マップされたエンティティへの射影は、Linq-to-objectsのマテリアライズされたデータに対してのみ実行できます。

編集:

EFがどのように機能するかについてはおそらく誤解があります。EFはエンティティの上で機能します-エンティティはあなたがマッピングしたものです。500列をエンティティにマップする場合、EFは定義したとおりにそのエンティティを使用するだけです。これは、クエリがエンティティをロードし、永続化することでエンティティが保存されることを意味します。

なぜこのように機能するのですか?エンティティはアトミックデータ構造と見なされ、そのデータは1回だけロードおよび追跡できます。これは、変更をデータベースに正しく永続化する機能の重要な機能です。必要に応じて列のサブセットだけをロードする必要がないという意味ではありませんが、列のサブセットをロードしても元のエンティティが定義されないことを理解する必要があります。これは、エンティティ内のデータの任意のビューと見なされます。このビューは追跡されず、追加の作業なしにデータベースに永続化することはできません(EFが投影の起点に関する情報を保持していないためです)。

EFは、エンティティをマップする機能にもいくつかの追加の制約を課します

  • 通常、各テーブルは1回だけマップできます。なんで?繰り返しになりますが、テーブルを異なるエンティティに複数回マッピングすると、それらのエンティティを正しく永続化する機能が損なわれる可能性があります。たとえば、非キー列が2回マッピングされ、同じレコードにマッピングされた両方のエンティティのインスタンスをロードした場合、マッピングされた値のどちらを使用しますか。変更を保存しますか?
  • テーブルを複数回マッピングできる2つの例外があります
    • 階層ごとのテーブルの継承-これは、継承階層で定義された複数のエンティティタイプのレコードをテーブルに含めることができるマッピングです。階層内の基本エンティティにマップされた列は、すべてのエンティティで共有する必要があります。すべての派生エンティティタイプは、特定のプロパティにマップされた独自の列を持つことができます(他のエンティティタイプでは、これらの列は常に空になります)。派生プロパティの列を複数のエンティティ間で共有することはできません。また、レコードに格納されているエンティティタイプをEFに通知するdiscriminatorと呼ばれる追加の列が1つ必要です。この列は、タイプdiscriminatorとして既にマップされているため、プロパティとしてマップできません。
    • テーブル分割-これは、単一テーブルマッピングの制限に対する直接的な解決策です。これにより、いくつかの制約付きでテーブルを複数のエンティティに分割できます。
      • エンティティ間には1対1の関係が必要です。コアデータのロードに使用される中央エンティティが1つあり、他のすべてのエンティティには、このエンティティからナビゲーションプロパティを介してアクセスできます。積極的な読み込み、遅延読み込み、明示的な読み込みは正常に機能します。
      • 関係は実数1-1であるため、両方の部分または関係が常に存在する必要があります。
      • エンティティは、キー以外のプロパティを共有してはなりません。変更可能な各プロパティは1回だけマップされるため、この制約によって最初の問題が解決されます。
      • 分割テーブルのすべてのエンティティには、マップされたキープロパティが必要です
      • 他のエンティティにはマップされた必要な列を含めることができるため、挿入にはオブジェクトグラフ全体を入力する必要があります

Linq-to-Sqlには、列を遅延読み込みとしてマークする機能も含まれていますが、この機能は現在EFでは使用できません。この機能に投票できます。

それは最適化のためのあなたのオプションにつながります

  • 投影法を使用して、エンティティの読み取り専用の「ビュー」を取得します
    • この回答の前の部分で示したように、Linqクエリでそれを行うことができます
    • データベースビューを作成し、それを新しい「エンティティ」としてマップできます
    • EDMXでは、「クエリの定義」または「クエリビュー」を使用して、マッピングにSQLまたはESQLプロジェクションをカプセル化することもできます。
  • テーブル分割を使用する
    • EDMXを使用すると、問題なくテーブルを多くのエンティティに分割できます
    • コードを最初に使用するとテーブルを分割することもできますが、テーブルを3つ以上のエンティティに分割する場合は、いくつかの問題があります(各エンティティタイプには、分割テーブルから他のすべてのエンティティタイプへのナビゲーションプロパティが必要です。これにより、使用が非常に困難になります。 )。
于 2012-07-17T19:00:36.097 に答える
0

必要な列数を照会するストアドプロシージャを作成し、コードからストアドプロシージャを呼び出します。

于 2015-10-19T18:02:46.177 に答える