1

コード :

IList<Evento> Eventi = new List<Evento>() { };

Eventi = (from Evento ae in new Eventi()
             select ae).ToList();

if (strNome != "")
{
    Eventi = Eventi.Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "").ToList();
}

if (strComune != "")
{
    Eventi = Eventi.Where(e => e.Comune != null && e.IDComune == strComune).ToList();
}

if (strMesi != "")
{
    Eventi = Eventi.Where(e => MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())).ToList();
}

コードの実行中に、すべてのクエリが 1 つの LINQ ステートメントだけにマージされることを私は知っています。しかし、ご覧のとおり、List -> ToList() を何度も変換しています。時間を無駄にするのはここだけだと思いますよね?これを回避してパフォーマンスを向上させるにはどうすればよいですか?

4

4 に答える 4

4

リスト/ToList が多いのはなぜですか? IEnumerable/IQueryable の何が問題になっていますか?

var eventi = (from Evento ae in new Eventi() 
             select ae);

if (strNome != "") 
{ 
    eventi = eventi.Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "");
} 

if (strComune != "") 
{ 
    eventi = eventi.Where(e => e.Comune != null && e.IDComune == strComune);
} 

if (strMesi != "") 
{ 
    eventi = eventi.Where(e => MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString()));
} 

// if you do need a list, then do so right at the end
var results = eventi.ToList();

編集:Caesayのいくつかの原則を明確にする

Caesay さん、時間を割いて実装をテストし、遅延読み込みが意図したとおりに動作することを確認していただきありがとうございます。多くの称賛!

上記のアプローチが実行時に最適化されているのに対し、コンパイル時に最適化されているというコメントに同意しない理由を説明したかったのです。

上記のアプローチは、より適切な説明がないため、意図したアプローチです。これは、eventiへの割り当てが、IEnumerable/IQueryable のソースに式を正しく追加しているためです。

あなたのアプローチは、 Func(Of T, TResult)がSelectWhereなどの拡張機能に渡されることを期待する、Linq to Entities などの特定のプロバイダーによってのみサポートされています。Entity Framework や Linq to Sql プロバイダーなどの多くのプロバイダーは、IEnumerableを実装するIQueryableを提供します。ただし、ここでの違いは、IQueryableSelectWhereなどは、 Expression(Of Func(Of T, TResult))を渡すことを想定していることです。

そのような場合、Expression は複数行のラムダをサポートしていないため、コードは期待どおりに (または少なくとも私が期待するようには) 動作しませんが、コンパイラはステートメントを正しく解釈して Expression> にコンパイルします。

簡単な例として:

public void Test<T1, T2>(System.Linq.Expressions.Expression<Func<T1, T2>> arg)
{
    throw new NotImplementedException();
}

public void Test()
{
    Test((string x) => x.ToLower());
    Test((string x) =>
    {
        return x.ToLower();
    });
}

上記の例では、最初の式はまったく問題ありません。あなたの例に大まかに基づいている2番目は、例外で失敗します:

A lambda expression with a statement body cannot be converted to an expression tree

コンパイラは、ステートメントを、IEnumerable でサポートされていることを認識しているFuncとして認識する場合があります。その結果、データベースへのクエリには Where 式が含まれず、データ ソース全体が返されます。データ ソースがインメモリになると、IEnumerable Where 句が適用されます。個人的には、必要以上のデータを返すために帯域幅を浪費しないように、これらの種類のものをデータベースに渡すことを非常に好みます。ケース) インメモリで行うよりも優れています。

それが理にかなっていて、あなたに役立つことを願っていますか?

于 2012-05-17T07:22:08.443 に答える
0

次のように、すべてを1つのlinqクエリに結合します。

        var eventi = from Evento e in new Eventi() select e;

        eventi = eventi.Where(e =>
        {
            if (strNome != "")
            {
                if(!(e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != ""))
                    return false;
            }
            if (strComune != "")
            {
                if(!(e.Comune != null && e.IDComune == strComune))
                    return false;
            }
            if (strMesi != "")
            {
                if(!(MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())))
                    return false;
            }

            return true;
        });

        var results = eventi.ToList();

これは論理的にはコードと同等ですが、はるかに高速であるはずです。テストできませんでしたが、コンパイルできないので。

于 2012-05-17T08:04:22.923 に答える
0

流暢な構文を使用して開始できます (List を避けるため)。

または、1 つのクエリで条件を組み合わせることができます。

Eventi =(new Eventi()).Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "" && e.Comune != null && e.IDComune == strComune &&MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())).ToList();

クエリ構文で同様に使用したように、Eventi は IEnumerable < Evento > を実装すると想定しています。

于 2012-05-17T07:23:15.277 に答える
0

strNome が空でないことをテストすると、最初の Where 句の後半が呼び出されることはありません。

そう e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "" 書けるe.Titolo.ToLower().Contains(strNome.ToLower())

strNome.ToLower()ラムダの外で計算して、一度だけ計算されるようにすることもできます。

さらに、他の人が提案したように、 Where 句を合理化し、 ToList() を削除できます。

知っておくべきもう 1 つの選択肢は、LinqKit です。これにより、ラムダ式をより簡単に組み合わせることができます。これWhere ... Whereは、「And」には十分であるため、この場合は必要ありませんが、いつか「Or」が必要になり、別の式が必要になる場合があります。解決。

または、ここで説明するメソッドを使用して独自のメソッドと Expression 'magic' を実行するメソッドを作成AndOr、Linq-to-Sql またはその他の Linq プロバイダーに渡すことができる単一の式を提供します。

于 2012-05-17T07:38:13.427 に答える