我在分层架构中使用Entity Framework POCO。我们应该在获得权利(y / ies)之后断开工作 假设我们有两个实体:
public class Customer
{
public int Id;
public string Name;
public virtual IList<Order> Orders;
}
public class Order
{
public int Id;
....
}
并且假设有一个客户的订单数量为1000 在这种情况下,我们希望获得该客户的订单,该订单仅在本周以服务方式完成 我们应该如何使用Repository方法和Service方法?
编辑
我想我应该扩展我的问题 首先,我的意思是“有1000个订单的客户”,我不想得到那个客户。我想获得“客户的订单(具有已知的Id,假设,Customer.Id = 5),Order.Date&gt; DateTime.Now.AddDays(-7)”。 表示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层最佳实践是否正确?由于订单不是“聚合根”,因此客户是“聚合根”
- 我是否必须在CustomerService类或OrderService类中使用此GetOrdersInLastWeek?
- 对我来说最后也是最重要的一个;如果我有像GetOrdersInLastWeek这样的方法,以及其他方法,那么其他层中的“Customer.Orders”导航属性(例如表示层)(假设我们正在使用POCO实体并断开连接)?
- 另一个例子;我想在服务方法中对Customer.Orders导航属性进行分页。我如何以及在哪里这样做(我知道该怎么做,但我的意思是根据最佳实践)?
答案 0 :(得分:1)
您可以尝试为此目的使用热切和显式加载的组合,例如使用DbContext
(EF =&gt; 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();
}
关于您的问题:
我是否必须在CustomerService中拥有此GetOrdersInLastWeek class,还是OrderService类?
在CustomerService
。因为您正在加载特定客户的数据。但在我看来,使用OrderService
也没有错。
我想对Customer.Orders中的导航属性进行分页 服务方式。我如何以及在哪里这样做(我知道该怎么做,但是 我的意思是根据最佳实践)?
使用您当前的体系结构,您必须在服务方法中执行此操作(使用Skip
和Take
创建查询),因为您正在暴露内存中的集合,即来自服务方法的物化结果。因此,您不应该在服务之外进行分页,因为它会强制您在可以分页之前加载所有数据。在我看来,唯一的选择是从服务返回IQueryable<T>
,然后通过向查询添加Skip
和Take
来在UI层中进行分页。但这意味着您无法在UI层中断开连接。