5

私は、POCOFirstアプローチでEntityFrameworkを使用しています。私は、スティーブ・サンダーソンが著書「Pro ASP.NET MVC 3 Framework」で説明したパターンに従い、DIコンテナーとDbContextクラスを使用してSQLServerに接続しました。

SQL Serverの基になるテーブルには、さまざまなアプリケーションで使用される非常に大きなデータセットが含まれています。このため、アプリケーションで必要なエンティティのビューを作成する必要がありました。

class RemoteServerContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Contact> Contacts { get; set; }
    ...

    protected override void  OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>().ToTable("vw_Customers");
        modelBuilder.Entity<Order>().ToTable("vw_Orders");
        ...
    }
}

これは私のニーズのほとんどでうまく機能しているようです。

私が抱えている問題は、これらのビューの一部に大量のデータが含まれているため、次のように呼び出すと次のようになることです。

var customers = _repository.Customers().Where(c => c.Location == location).Where(...);

データセット全体が戻ってきているようです。これは、LINQクエリがセットを必要なものに減らすまでに時間がかかる場合があります。基準が少数のレコードにのみ適用可能であり、SQLサーバーからデータセット全体を取得している場合、これは非常に非効率的です。

次のようなストアドプロシージャを使用して、これを回避しようとしました。

public IEnumerable<Customer> CustomersThatMatchACriteria(string criteria1, string criteria2, ...) //or an object passed in!
{
    return Database.SqlQuery<Customer>("Exec pp_GetCustomersForCriteria @crit1 = {0}, @crit2 = {1}...", criteria1, criteria2,...);
}

これははるかに高速ですが、ここでの問題は、DbSetが返されないため、オブジェクト間の接続がすべて失われることです。たとえば、IDを含めても、注文や連絡先などの関連オブジェクトを参照できません。これは、戻りタイプが「顧客」のDbSetではなく「顧客」のコレクションであるためです。

未使用のデータを大量に渡さないように、SQLサーバーにクエリを実行させるより良い方法はありますか?

4

4 に答える 4

4
var customers = _repository.Customers().Where(c => c.Location == location).Where(...

Customers()を返す場合IQueryable、このステートメントだけでは実際には何も「戻さない」ことになります。を呼び出すと別Whereのが得られます。クエリを実行する原因となる何か(、、など)を実行するまで、実際に何かが実行されることはありません。結果が返されました。IQueryableIQueryableToListFirstOrDefault

ただし、このCustomersメソッドがインスタンス化されたオブジェクトのコレクションを返す場合は、はい。すべてのオブジェクトを取得しているすべてのオブジェクトを要求しているためです。

私はコードファーストまたは実際にリポジトリパターンを使用したことがないので、IQueryableできるだけ長く領域にとどまり、すべてを適用した後にのみクエリを実行する以外に、何をアドバイスすべきかわかりません関連するフィルター。

于 2012-05-15T08:48:08.033 に答える
2

データセットだけを返すために私がしたことは、次のようになります。

var customers = (from x in Repository.Customers where <boolean statement> &&/|| <boolean statement select new {variableName = x.Name , ...).Take(<integer amount for amount of records you need>);

たとえば、次のようになります。

var customers = (from x in _repository.Customers where x.ID == id select new {variableName = x.Name} ).take(1000);

次に、結果を反復処理してデータを取得します:(linqステートメントはIQueryableを返すことを忘れないでください)...

foreach (var data in customers)
{
   string doSomething = data.variableName; //to get data from your query.
}

これが役立つことを願っていますが、まったく同じ方法ではありませんが、コードでこれが便利だと思います

于 2012-05-15T09:00:59.197 に答える
1

おそらく、リポジトリ内のCusomters()メソッドがGetAll()のようなことを実行し、最初にリスト全体をフェッチしているためです。これにより、LINQとSQLServerがスマートクエリを作成できなくなります。

リポジトリに適切な回避策があるかどうかはわかりませんが、次のようなことを行う場合は次のようになります。

using(var db = new RemoteServerContext())
{
  var custs = db.Customers.Where(...);
}

私はそれがはるかに速くなると思います。プロジェクトが十分に小さい場合は、リポジトリなしで実行できます。もちろん、抽象化レイヤーは失われますが、小さなプロジェクトでは、これは大きな問題ではないかもしれません。

一方、リポジトリ内のすべての顧客を一度ロードして、結果のコレクションを直接使用することができます(リストを埋めるメソッド呼び出しの代わりに)。ただし、顧客の追加、削除、変更には注意してください。

于 2012-05-15T09:05:14.450 に答える
0

topSQLの関数のようなSQLページングのような少ないデータを返すか、ストアドプロシージャを使用して手動クエリを実行するには、LINQクエリが必要です。いずれの場合も、クエリメカニズムを書き直す必要があります。これが、私がEFを使用しなかった理由の1つです。これは、コードをあまり制御できないためです。

于 2012-05-15T08:41:15.543 に答える