10

LINQ to SQL クエリから返される列の数を動的に制限することはできますか?

50 列を超えるデータベース SQL ビューがあります。私のアプリには、各列に 1 つずつ、50 を超えるプロパティを持つドメイン オブジェクトがあります。私の winforms プロジェクトでは、ドメイン オブジェクトのリストをグリッドにバインドします。デフォルトでは、いくつかの列のみが表示されますが、ユーザーは任意の列のオン/オフを切り替えることができます。

ユーザーは、グリッドの読み込みに時間がかかりすぎると不満を漏らしています。LINQ で生成された SQL クエリをキャプチャし、それを SQL Server Management Studio 内で実行して、遅いことを確認しました。非表示の列をすべて削除して SQL ステートメントを変更すると、ほぼ瞬時に実行されます。パフォーマンスとクエリ内の列数の間には直接的な相関関係があります。

LINQ で生成された SQL クエリから返される列の数を動的に変更できるかどうか疑問に思っていますか? たとえば、現在のコードは次のようになります。

public List<Entity> GetEntities()
{
    using (var context = new CensusEntities())
    {
        return (from e in context.Entities
            select e).ToList();
    }
}

context.Entities オブジェクトは、50 を超える列を含む SQL ビューから生成されたため、上記を実行すると、「SELECT Col1、Col2、Col3、... Col50 FROM Entity INNER JOIN...」のような SQL が生成されます。メソッドのシグネチャを次のように変更したいと思います。

public List<Entity> GetEntities(string[] visibleColumns)
{
    using (var context = new CensusEntities())
    {
        return (from e in context.Entities
            select e).ToList();
    }
}

このメソッドの本体を変更して、生成された SQL ステートメントを変更して、気になる列の値のみを返す方法がわかりません。他のすべての値は NULL にすることができます。

4

3 に答える 3

4

このようなものが動作するはずです:

 List<string> columns = new List<string>();
 columns.Add("EmployeeID");
 columns.Add("HireDate");
 columns.Add("City");

リストに列を追加します ^.

var result = Class.ReturnList(columns);  

List をメソッド ^ に渡します。

public static List<Entity> ReturnList(List<string> VisibleColumns)
        {
            StringBuilder SqlStatement = new StringBuilder();
            SqlStatement.Append("Select ");
            for (int i = 0; i < VisibleColumns.Count; i++)
            {
                if (i == VisibleColumns.Count - 1)
                {
                    SqlStatement.Append(VisibleColumns[i]);
                }
                else
                {
                    SqlStatement.Append(VisibleColumns[i]);
                    SqlStatement.Append(",");
                }
            }
            SqlStatement.Append(" FROM Entity");
            using (var ctx = new DataClasses1DataContext())
            {
                var result = ctx.ExecuteQuery<Entity>(SqlStatement.ToString());
                return result.ToList();
            }

        }

これは基本的に、リストSELECTで渡したすべてのフィールドでステートメントを作成するだけです。VisibleColumns

VisibleColumnsこの場合、リスト内の文字列によって生成される SQL ステートメントは次のとおりです。

Select EmployeeID, HireDate, City From Employee

(注:これを試すためにNorthwindデータベースを使用したため、EmployeeIDなどの列名。明らかに、それらを独自のものに置き換える必要があります。)

于 2012-10-09T21:04:17.293 に答える
0

これを動的に行うのは簡単ではありませんが、取得したい列の組み合わせのセットが限られている場合は、次のように明示的な選択を行うことができます。

public List<Entity> GetEntities()
{
    using (var context = new CensusEntities())
    {
        return (from e in context.Entities
            select new
            {
                col1 = e.col1,
                col4 = e.col4,
                col5 = e.col5,
            }
        ).ToList()
        .Select(x=>new Entity{col1 = x.col1, col4 = x.col4, col5 = x.col5}).ToList();
    }
}

LINQ2SQL は部分的なエンティティを作成しないため、追加の選択手順が必要です。

ユーザーが取得したい列の一般的な組み合わせ (特に最初の列) ごとにメソッドを作成します。

ただし、これを動的にするために、匿名クラスにプロパティとして格納されたエンティティを使用してクエリを作成し、同じ匿名クラスの 2 番目のプロパティの別の匿名クラスで結果プロパティを収集できます。最後に、収集したオブジェクトからエンティティを選択して、正しいタイプのオブジェクトにします。

public List<Entity> GetEntities()
{
    using (var context = new CensusEntities())
    {
        var combinedResult = (from e in context.Entities
            select new {
                Entity = e,
                CollectedValues = new
                                  {
                                      // Insert default values of the correct type as placeholders
                                      col1 = 0, // or "" for string or false for bool
                                      col2 = 0, // or "" for string or false for bool
                                      // ...
                                      col49 = 0, // or "" for string or false for bool
                                      col50 = 0, // or "" for string or false for bool
                                  }
        );

        // Then copy each requested property

        // col1
        if (useCol1)
        {
            var combinedResult = (from e in combinedResult
                select new {
                    Entity = e,
                    CollectedValues = new
                                      {
                                          col1 = e.Enitity.col1, // <-- here we update with the real value
                                          col2 = e.CollectedValues.col2, // <-- here we just use any previous value
                                          // ...
                                          col49 = e.CollectedValues.col49, // <-- here we just use any previous value
                                          col50 = e.CollectedValues.col50, // <-- here we just use any previous value                                          }
            );
        }

        // col2
        if (useCol2)
        {
         // same as last time
                                          col1 = e.CollectedValues.col1, // <-- here we just use any previous value
                                          col2 = e.Enitity.col2, // <-- here we update with the real value
                                          // ...
        }

        // repeat for all columns, update the column you want to fetch

        // Just get the collected objects, discard the temporary
        // Entity property. When the query is executed here only
        // The properties we actually have used from the Entity object
        // will be fetched from the database and mapped.
        return combinedResult.Select(x => x.CollectedValues).ToList()
        .Select(x=>new Entity{col1 = x.col1, col2 = x.col2, ... col50 = x.col50}).ToList();
    }
}

多くのコードがあり、維持するのは面倒ですが、うまくいくはずです。
このルートに進む場合は、LINQ コンテキストからのリフレクションを使用してこのコードをビルドするコード ジェネレーターを作成することをお勧めします。

于 2012-10-09T19:55:22.077 に答える
0

このようなことを試してください

using (var context = new CensusEntities())
{
    var q = from e in context.Entities
        select e.myfield1,e.myfield2;
    return q.Tolist();
}

結果のクエリは軽くなり、その下にあるすべてのデータ変換も軽くなるはずです。

しかし、本当に動的入力を作成する必要がある場合は、動的 SQL を使用する必要があると思います。そう

  1. 動的 SQL を作成してデータ テーブルを取得する
  2. ここに示すように、データ テーブルを動的オブジェクトへの変換に使用します。DataTable を動的オブジェクト に変換するにはどうすればよいですか?

ところで、多くのハードワークがあります。コードの最初のブロックの使用を検討する必要があると思います。

于 2012-10-09T20:21:26.017 に答える