22

次のことが可能だと感じました。どのようなアプローチを取るべきかわかりません。

私がやりたいのは、includeメソッドを使用して結果を形成することです。つまり、オブジェクトグラフに沿ってトラバースする距離を定義します。しかし...私はそのトラバーサルを条件付きにしたいと思います。

something like...

dealerships
    .include( d => d.parts.where(p => p.price < 100.00))
    .include( d => d.parts.suppliers.where(s => s.country == "brazil"));

これは有効なlinqではなく、実際にはひどく間違っていることを理解していますが、基本的には、次のような形の結果を返す式ツリーを構築する方法を探しています...

select *
from dealerships as d
outer join parts as p on d.dealerid = p.dealerid
    and p.price < 100.00
outer join suppliers as s on p.partid = s.partid
    and s.country = 'brazil'

結合条件に重点を置いています。

これはesqlを使用するとかなり簡単なように感じますが、私の好みはその場で式ツリーを作成することです。

いつものように、アドバイスやガイダンスに感謝します

4

5 に答える 5

15

これでうまくいくはずです:

using (TestEntities db = new TestEntities())
{
    var query = from d in db.Dealership
                select new
                {
                    Dealer = d,
                    Parts = d.Part.Where
                    (
                        p => p.Price < 100.0 
                             && p.Supplier.Country == "Brazil"
                    ),
                    Suppliers = d.Part.Select(p => p.Supplier)
                };

    var dealers = query.ToArray().Select(o => o.Dealer);
    foreach (var dealer in dealers)
    {
        Console.WriteLine(dealer.Name);
        foreach (var part in dealer.Part)
        {
            Console.WriteLine("  " + part.PartId + ", " + part.Price);
            Console.WriteLine
                (
                "  " 
                + part.Supplier.Name 
                + ", " 
                + part.Supplier.Country
                );
        }
    }
}

このコードは、それぞれがフィルター処理された部品のリストを含むディーラーのリストを提供します。各部分はサプライヤーを参照します。興味深いのは、示されている方法でselectで匿名タイプを作成する必要があることです。それ以外の場合、DealershipオブジェクトのPartプロパティは空になります。

また、クエリからディーラーを選択する前に、SQLステートメントを実行する必要があります。そうしないと、ディーラーのPartプロパティが再び空になります。そのため、ToArray()呼び出しを次の行に配置します。

var dealers = query.ToArray().Select(o => o.Dealer);

しかし、私はこれがあなたの図書館のユーザーが期待しているものではないかもしれないというダレンに同意します。

于 2009-07-22T09:45:16.130 に答える
7

これがあなたが望むものであると確信していますか?私が尋ねる唯一の理由は、ディーラーのパーツにフィルターを追加すると、結果はディーラーではなくなるということです。ほとんどの場合、ディーラーに非常に近い(同じプロパティを持つ)特別なオブジェクトを扱っていますが、「パーツ」プロパティの意味は異なります。ディーラーとパーツの関係ではなく、フィルター処理された関係です。

言い換えれば、あなたの結果からディーラーを引き出して、私が書いたメソッドに渡した場合、私のメソッドでは次のように呼び出します。

var count = dealership.Parts.Count();

価格が100ドル未満のブラジルからのフィルター処理された部品ではなく、部品を入手することを期待しています。

フィルタリングされたデータを渡すためにディーラーオブジェクトを使用しない場合、それは非常に簡単になります。それは次のように簡単になります:

    var query = from d in dealerships
               select new { DealershipName = d.Name, 
CheapBrazilProducts = dealership.Parts.Where(d => d.parts.Any(p => p.price < 100.00) || d.parts.suppliers.Any(s => s.country == "brazil")) };

要求されたようにフィルタリングされたセットを取得する必要がある場合は、おそらく上記の手法を使用してから、Automapperなどのツールを使用して、フィルタリングされた結果を匿名クラスから実際のクラスにコピーします。信じられないほどエレガントではありませんが、機能するはずです。

お役に立てば幸いです。それは興味深い問題でした。

于 2009-07-21T18:14:06.973 に答える
1

私は何かが足りないのですか、それともAnyキーワードを探しているだけではありませんか?

var query = dealerships.Where(d => d.parts.Any(p => p.price < 100.00) || 
                              d.parts.suppliers.Any(s => s.country == "brazil"));
于 2009-07-06T04:52:41.477 に答える
1

はい、それが私がやりたかったことです。Data Services の次のリリースでは、その LINQ to REST クエリを実行できる可能性があると思います。それまでの間、逆をロードするように切り替えて、関連するエンティティを含めます。複数回ロードされますが、理論的には、このコードのように最初のインクルードで一度だけロードする必要があります

return this.Context.SearchHistories.Include("Handle")
    .Where(sh => sh.SearchTerm.Contains(searchTerm) && sh.Timestamp > minDate && sh.Timestamp < maxDate);

ロジックに一致する任意のハンドルをロードしようとする前に、投稿したインクルードロジックを使用する方法がわからないので、逆ルックアップはそれほど汚れていないソリューションになると思います

于 2009-09-22T01:02:23.247 に答える