Linq to sql 通过一对多查找优化Linq到Sql的映射

Linq to sql 通过一对多查找优化Linq到Sql的映射,linq-to-sql,database-design,optimization,orm,entity-relationship,Linq To Sql,Database Design,Optimization,Orm,Entity Relationship,我在使用以下数据结构优化数据查找时遇到问题: Order ----- Id Customer Date ... etc OrderStatus ------ Id OrderId Date UpdatedBy StatusTypeId ...etc 这让我在订单列表页面感到头疼,该页面基本上显示了一个订单列表。列表中的每个订单摘要显示了来自订单和当前订单状态的一系列字段,即带有最新日期的订单状态,链接到订单 Order List --------------------------

我在使用以下数据结构优化数据查找时遇到问题:

Order
----- 
Id 
Customer 
Date 
... etc


OrderStatus
------
Id
OrderId
Date
UpdatedBy
StatusTypeId
...etc
这让我在订单列表页面感到头疼,该页面基本上显示了一个订单列表。列表中的每个订单摘要显示了来自
订单
和当前
订单状态
的一系列字段,即带有最新
日期的
订单状态
,链接到
订单

Order List
-------------------------------------------------------
Order Id | Customer     | Order Date  | CurrentStatus |
-------------------------------------------------------
1        | Someone      |  1.10.2010  | Completed     |
-------------------------------------------------------
2        | Someone else | 12.10.2010  | In Progress   |
-------------------------------------------------------
3        | Whoever      | 17.10.2010  | On Hold       |
-------------------------------------------------------
现在,假设我想列出今年的所有订单。我的存储库获取
顺序
对象

var orders=\u repository.GetAllOrdersSinceDate(dt)

现在我的结局是

foreach (Order order in orders)
{
    OrderSummary summary = new OrderSummary();
    summary.Customer = order.Customer;
    summary.Date = order.Date;
    // ...etc

    // problem here!!
    summary.OrderStatus = order.OrderStatus
                .OrderByDescending(s => status.Date).First();
}
Order
----- 
Id 
Customer 
Date 
CurrentStatusTypeId
CurrentStatusDate
CurrentStatusUpdatedBy
...etc


OrderStatusHistory
------
Id
OrderId
Date
UpdatedBy
StatusTypeId
...etc
因此,对于返回的每个
订单
,我最后得到的是
SELECT
语句,然后是
SELECT
语句,该语句位于
OrderStatus

因此,要显示今年所有记录的摘要,需要大约20000个单独的SQL查询,并且需要花费许多分钟来加载

有什么好办法解决这个问题吗

我正在考虑重新编写数据库,以便在
Order
表中保存当前的
OrderStatus
,因此我最终得到了如下结果

foreach (Order order in orders)
{
    OrderSummary summary = new OrderSummary();
    summary.Customer = order.Customer;
    summary.Date = order.Date;
    // ...etc

    // problem here!!
    summary.OrderStatus = order.OrderStatus
                .OrderByDescending(s => status.Date).First();
}
Order
----- 
Id 
Customer 
Date 
CurrentStatusTypeId
CurrentStatusDate
CurrentStatusUpdatedBy
...etc


OrderStatusHistory
------
Id
OrderId
Date
UpdatedBy
StatusTypeId
...etc
这是我能看到的解决问题的唯一方法,但似乎是一个相当糟糕的解决方案


这里最好的方法是什么?

您可以创建DataLoadOptions对象,如下所示:

DataContext db = new DataContext
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<OrderStatus>(c => c.Orders);
db.LoadOptions = ds;
DataContext db=newdatacontext
DataLoadOptions ds=新的DataLoadOptions();
ds.LoadWith(c=>c.Orders);
db.LoadOptions=ds;

然后,当您运行查询时,它应该预取OrderStatus表

请不要为了解决问题而对数据库模型进行反规范化。这只会让事情变得更糟。您可以通过编写一个服务方法来解决这个问题,该方法返回数据传输对象(DTO)列表,而不是LINQ to SQL实体。例如,服务方法可能如下所示:

public OrderSummary[] GetOrderSummariesSinceDate(DateTime d)
{
    return (
        from order in this.context.Orders
        where order.Date >= d
        let lastStatus = (
            from status in order.OrderStatusses
            orderby status.Date descending
            select status).First()
        select new OrderSummary
        {
            OrderId = order.Id,
            CustomerName = order.Customer.Name,
            Date = order.Date,
            OrderStatus = lastStatus.StatusType.Name
        }).ToArray();    
}
注意以下几点:

  • 此代码将作为数据库中的单个SQL查询执行
  • 此方法将返回一个仅包含客户端所需数据的对象,但仅此而已。无
    客户
    对象,无
    订单状态
    对象
  • 通过调用
    ToArray
    ,我们可以确保在此时查询数据库,并且不会延迟
这三点确保了性能的最大化,并允许服务层控制对数据库执行的操作


我希望这会有所帮助。

这确实提高了性能,但仍有改进的余地
LoadWith
将从数据库中获取每个
订单的所有
OrderStatus
记录,而每个订单只需要最后一个
OrderStatus
。这有点帮助,但没有帮助。我知道我需要做这样的事情,但它充满了问题。我的订单对象位于域层。我的OrderSummary对象是演示层中ViewModel的一部分。我的OrderRepository甚至不知道OrderSummary存在。我的OrderRepository封装了一个通用的Linq响应库,这给了我相当有限的控制。我使用的是DTO,但除了使用GetCurrentStatus()方法返回Order对象(这是我自己的Order类,不是Linq生成的类)之外,我仍然无法返回太多。您可以将
OrderSummary
移动到服务层,或者定义一个DTO并将其映射到表示层中的ViewModel。您需要在此级别使用DTO以获得良好的性能。如果您的存储库有限,也许您应该采取不同的方法。例如,在存储库上实现IQueryable。在这里寻找灵感:。