1

階層化アーキテクチャでEntityFrameworkPOCOを使用しています。entit(y / ies)を取得した後、切断して作業する必要があります。
2つのエンティティがあると仮定します。

public class Customer
{  
  public int Id;  
  public string Name;
  public virtual IList<Order> Orders;
}  

public class Order
{
  public int Id;
  ....
}

また、注文数が1000の顧客が1人いると仮定します
。この場合、サービス方式で今週のみ行われたこの顧客の注文を取得します。
リポジトリメソッドとサービスメソッドはどのようにすべきですか?

編集

私は私の質問を拡張する必要があると思います。
まず第一に、私は「1000注文の顧客」という意味で、その顧客を獲得したくありません。「Order.Date>DateTime.Now.AddDays(-7)である顧客の注文(既知のID、仮定、Customer.Id = 5)」を取得したいと思います。
IQueryableオブジェクトを表すのは簡単です。

public List<Order> GetOrdersInLastWeek(int CustomerId)  
{  
  Customer customer = (from c in ctx.Customers where c.Id == CustomerId).SingleOrDefault();  
  List<Order> ordersThatIWant = customer.Orders.Where(o => o.Date > DateTime.Now.AddDays(-7)).ToList();
  return ordersThatIWant;  
}

私はこれらについて興味があります:上記のコードはうまく動作します。
-しかし、それはORM / Nレイヤーのベストプラクティスにとって正しいのでしょうか?Orderは「集約ルート」ではないため、Customerは「集約ルート」です。
-このGetOrdersInLastWeekをCustomerServiceクラスまたはOrderServiceクラスに含める必要がありますか?
-そして私にとって最後のそして重要なもの。GetOrdersInLastWeekのようなメソッド、およびこのような他のメソッドがある場合、他のレイヤー(プレゼンテーション層など)の「Customer.Orders」ナビゲーションプロパティはどうですか(POCOエンティティを操作していて切断されていると仮定します)。
- もう一つの例; serviceメソッドのCustomer.Ordersナビゲーションプロパティでページングを実行したい。どこでどのようにこれを行うことができますか(私はそれを行う方法を知っていますが、ベストプラクティスに従って意味します)?

4

1 に答える 1

1

この目的のために、熱心な読み込みと明示的な読み込みを組み合わせて使用​​することができます。たとえば、DbContext(EF => 4.1)のようになります。

public List<Customer> GetCustomersWithOrders()
{
    using (var ctx = new MyDbContext())
    {
        var customers1 = ctx.Customers.Include(c => c.Orders)
            .Where(c => c.Orders.Count() < 1000)
            .AsEnumerable();

        var customers2 = ctx.Customers
            .Where(c => c.Orders.Count() >= 1000)
            .AsEnumerable();

        DayOfWeek today = DateTime.Now.DayOfWeek;
        DateTime monday = DateTime.Now.AddDays(-1*(today-DayOfWeek.Monday));
        DateTime sunday = monday.AddDays(6);
        foreach (var customer in customers2)
        {
            ctx.Entry(customer).Collection(c => c.Orders).Query()
                .Where(o => o.ShipDate >= monday && o.ShipDate <= sunday)
                .Load();
        }

        return customers1.Concat(customers2).ToList();
    }
}

結果は、1 + 1 + customers2.Countデータベースクエリの結果で構成されます。顧客が1000を超える注文をしているというケースがまれである場合、それらの複数のクエリがパフォーマンスの大きな問題になるとは思いません。

編集

クエリを変更することをお勧めします。問題は、顧客をロードし(クエリ1)、次にすべての注文の遅延ロードをトリガーすることです(クエリ2)。したがって、メモリにフィルタを適用する前に、すでに1000をはるかに超える注文をロードしている可能性があります。これを回避するには、次を使用します。

public List<Order> GetOrdersInLastWeek(int CustomerId)  
{  
    var date = DateTime.Now.AddDays(-7);
    var orders = ctx.Customers
        .Where(c => c.Id == CustomerId)
        .Select(c => c.Orders.Where(o => o.Date > date))
        .SingleOrDefault();

    if (orders == null)
        return null; // or create an empty list

    return orders.ToList();
}

あなたの質問について:

このGetOrdersInLastWeekをCustomerServiceクラスまたはOrderServiceクラスに含める必要がありますか?

CustomerService。特定の顧客のデータを読み込んでいるためです。しかしOrderService、私の意見では、を使用することもそれほど間違っていません。

serviceメソッドのCustomer.Ordersナビゲーションプロパティでページングを実行したい。どこでどのようにこれを行うことができますか(私はそれを行う方法を知っていますが、ベストプラクティスに従って意味します)?

現在のアーキテクチャでは、メモリ内のコレクション、つまりサービスメソッドからのマテリアライズされた結果を公開しているため、サービスメソッドでそれを行う必要があります(とを使用してクエリを作成しますSkip) 。したがって、ページングする前にすべてのデータTakeをロードする必要があるため、サービスの外部でページングしないでください。私の意見では、唯一の選択肢は、サービスから戻ってから、クエリにとを追加してUIレイヤーでページングすることです。ただし、UIレイヤーで切断できないことを意味します。IQueryable<T>SkipTake

于 2012-07-03T16:37:36.173 に答える