2

同じ複雑なWhere句を含むLinqからSQLへのクエリのペアがあります。具体的には次のとおりです。

where ((range.MinimumFrequency <= minFreq &&  minFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency <= maxFreq && maxFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency <= minFreq && maxFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency >= minFreq && maxFreq >= range.MaximumFrequency))

そして、このコードのチャンクをあちこちにコピーして貼り付けるのではなく、共有できる他の何かにリファクタリングしたかったのです。SQLに変換できないため、通常のメソッドではこれを実行できないことはわかっていますが、

式<機能<...>>

ここで説明されていることはどちらでも機能します。

ここで正気を保つためにwhere句を単純化すると、

where (range.MinumumFrequency < minFreq) 

式に入れるので、私は試しました:

public static Expression<Func<FreqRange, bool>> Overlaps(decimal minMHz, decimal maxMHz)
{
   return (range => range.MinimumFrequency <= minMHz);
}

これはコンパイルされているように見えますが、whereステートメントが機能しないようです。次のことを試しました。

where FreqRange.Overlaps(minMHz, maxMHz)

しかし、これによりコンパイル時エラーが発生します。

タイプ'System.Linq.Expressions.Expression>'を'bool'に暗黙的に変換することはできません

何か案は?また、これが機能すると仮定して、Expression <Func <>>のラムダ式を拡張して他の条件を含めることはできますか?

4

2 に答える 2

2

言語構築の LINQ 構文を使用する場合、暗黙的にラムバ式を宣言していることになります。そのラムバ式は- であるため、式を返すExpression<Func <>>ために where 句は必要ありません式である必要があります。

例えば

var q = from row in myTable
        where row.a < aMax
        select row.b;

// which translates to

var q = myTable.Where(row => row.a < aMax).Select(row => row.b);

ここで、必要に応じて の値row => row.a < aMaxだけでなく、「キャッシュ」する必要があります。では、こんなことを書くとしたら…row.a < aMax

Expression<Func<?,bool>> cachedExpression = row => row.a < aMax;

var q = from row in myTable
        where cachedExpression
        select row.b;

さて、あなたは「行が与えられた場合、(行が与えられた場合、row.a が aMax より小さいことが真である)」と言っています。これはナンセンスであり、cachedExpression が型Expression<Func<?,bool>>で、myTable が LinqToSql 提供のテーブルである場合はコンパイルされません。これは次のように変換されます。

Expression<Func<?,bool>> cachedExpression = row => row.a < aMax;

//nonsense .Where:
var q = myTable.Where(row => cachedExpression).Select(row => row.b);
//effectively says this:
var q = myTable.Where(row => (row0 => row0.a < aMax)).Select(row => row.b);

現在、これは、linq クエリ プロバイダーが非ブール値で whereclause を実装できるという意味では合法ですが、これを行うのは非常に奇妙なことです確かに、標準の linq プロバイダー (Linq to Sql など) はそのようなことを行いません。

それで、あなたは何をすべきですか?何かのようなもの:

//not .Where(row=>cachedExpression)!
var q = myTable.Where(cachedExpression).Select(row => row.b);

//or, alternatively:
var q = from filteredRow in myTable.Where(cachedExpression)
        select filteredRow.b;
于 2009-09-01T12:44:36.127 に答える
1

IQueryable を受け取って送信するメソッドを作成することもできます。これらのようなビューを使用しましたが、純粋にコードで使用しました。

public class WithProps
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public override string ToString()
    {
        return string.Format("{0}-{1}", Prop1, Prop2);
    }
}

public static class Tools
{
    public static IQueryable<WithProps> MyFilter(this IQueryable<WithProps> props)
    {
        return props.Where(p => p.Prop1 == "hi");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var propList = new List<WithProps>()
        {
            new WithProps(){ Prop1="hi", Prop2="there"},
            new WithProps(){ Prop1="hi", Prop2="bye"},
            new WithProps(){ Prop1="hello", Prop2="world"},
            new WithProps(){ Prop1="bye", Prop2="friend"}
        };

        var filtered = propList.AsQueryable().MyFilter();

        Console.WriteLine("propList ===");
        foreach (var item in propList)
            Console.WriteLine(item.ToString());
        Console.WriteLine("filtered ===");
        foreach (var item in filtered)
            Console.WriteLine(item.ToString());
    }
}

...結果...

propList ===
hi-there
hi-bye
hello-world
bye-friend
filtered ===
hi-there
hi-bye
于 2009-09-01T13:09:05.113 に答える