1

私は今、簡単な問題で丸2日間いじっています。

Product エンティティと ProductLocationHistory エンティティを含むデータベースがあります。ProductLocationHistory には、Storehouse、Contact、または Relation への参照があります。製品が移動するたびに新しいエントリが取得されるため、製品の過去をたどることができます。したがって、現在の場所は、ProductLocationHistory の DateCreation フィールドによって決定される最後のエントリです。

例:

var storehousesWithBorrowedItems = productService.GetAllProducts()
    .Select(p => p.ProductLocationHistories
        .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation)))
    .Select(plh => plh.Storehouse)
    .Distinct();

これらはすべて現在商品を持っている倉庫です。

もちろん、製品の現在の場所を特定する必要があるたびに、これをコードに書き出すのは非常に不便です。Product の現在の ProductLocationHistory への参照は、一貫性の問題が発生する可能性があるため、私の意見ではまったく望ましくありません。私は次のようなものを好むだろう:

Product.ProductLocationHistories.Current();

だから私は試しました:

public static ProductLocationHistory Current(this EntitySet<ProductLocationHistory> plhs)
    {
        return plhs.SingleOrDefault(plh => plh.DateCreation == plhs.Max(grp => grp.DateCreation));
    }

「Current has no supported translation to sql」が表示されるため、これはクエリ可能では機能しません。また、Product と ProductLocationHistory の組み合わせがクエリの「開始」であることが多いため、すぐに IEnumerable に変換するのではなく、IQueryable のままにしてクエリを実行する必要があります。商品ごとに現在地を特定!その後に何が続くかは言うまでもありません...エンティティの現在のログエントリはよく使用され、機能し、クエリ可能である限り、.Current() 関数がどれほど複雑であっても問題ありません。基になるコードがクエリ可能であるため、.Current(...) 関数が機能することを期待していましたが、それでも例外が発生します。最初の例のようにコードがインラインの場合、例外は発生しません。

Func、ProductLocationHistory>>、および Expression<...> などの可能性を調べましたが、探している例が見つかりませんでした。Product.CurrentProductLocationHistory() のようなソリューションは、さらに優れている可能性があります。絶対的な最善の解決策は、さらに一般的で、次の形式になります。

Current<T> (IQueryable<T> collection, string field) { return entity with max field of collection } 

私はこれを長い間試してきましたが、LINQ自体の内部関数(Any、First、Count、Max)も必要に応じてクエリ可能であるため、可能であるに違いないと確信しています。

アップデート

現在、次のように動作します。

 Expression<Func<Product, ProductLocationHistory>> expression = IQueryable.Current(null);
        var ken = productService.GetAllProducts()
            .Where(p => p.OnLoan)
            .Select(expression)
            .Where(plh => plh.Storehouse != null)
            .Select(plh => plh.Storehouse)
            .Distinct();

public static Expression<Func<Product, ProductLocationHistory>> Current(this EntitySet<ProductLocationHistory> productLocationHistories)
    {
        Expression<Func<Product, ProductLocationHistory>> expression = p => p.ProductLocationHistories
                                         .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(plhs => plhs.DateCreation));
        return expression;
    }

正しい方向への一歩ですが、私はまだ完全に満足していません. p.ProductLocationHistories().Current() を使用できるようにしたいので、探求を続けます。

ありがとうキリル!C# コードが SQL に変換されたのを見たのはこれが初めてです。正しい方向への素晴らしい一歩!

4

1 に答える 1

1

次の式でフィールドを設定できます。

Expression<Func<ProductLocationHistory, bool>> currentSelector = plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation)

どこでも使用できます:

var storehousesWithBorrowedItems = productService.GetAllProducts()
    .Select(p => p.ProductLocationHistories
        .SingleOrDefault(currentSelector ))
    .Select(plh => plh.Storehouse)
    .Distinct();
于 2012-11-17T08:08:45.023 に答える