Оптимизация сопоставления Linq-Sql с поиском один ко многим - PullRequest
0 голосов
/ 02 декабря 2010

У меня проблемы с оптимизацией поиска данных со следующей структурой данных:

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


OrderStatus
------
Id
OrderId
Date
UpdatedBy
StatusTypeId
...etc

Это вызывает у меня головную боль на странице Order List , которая в основном показывает список Orders. Каждый Сводка заказа в списке показывает группу полей от Order и текущего OrderStatus, то есть OrderStatus с самым последним Date, который связан с Order.

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       |
-------------------------------------------------------

Теперь, скажем, я хочу перечислить все заказы с этого года. Мой репозиторий извлекает Order объекты

var orders = _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();
}

В результате я получаю оператор SELECT для Order, а затем еще один оператор SELECT для OrderStatus для каждого Order возвращаемого значения.

Таким образом, для отображения сводки всех записей за этот год требуется около 20 000 отдельных запросов SQL и много минут загрузки.

Есть какой-нибудь аккуратный способ решить эту проблему?

Я подумываю переписать базу данных для хранения current OrderStatus в таблице Order, поэтому я получаю что-то вроде

Order
----- 
Id 
Customer 
Date 
CurrentStatusTypeId
CurrentStatusDate
CurrentStatusUpdatedBy
...etc


OrderStatusHistory
------
Id
OrderId
Date
UpdatedBy
StatusTypeId
...etc

это единственный способ, который я вижу, чтобы решить проблему, но кажется довольно неприятным решением.

Какой лучший путь вперед?

Ответы [ 2 ]

1 голос
/ 02 декабря 2010

Пожалуйста, не денормализуйте модель базы данных, чтобы решить вашу проблему.Это только усугубит ситуацию.Это можно исправить, написав метод службы, который возвращает список объектов передачи данных (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-запрос в базе данных.
  • Этот метод возвращает объект, который содержит только те данные, которые нужны клиенту, но не более того.Нет Customer объекта, нет OrderStatus объекта.
  • Вызывая ToArray, мы гарантируем, что к этому моменту база данных запрашивается и не откладывается.

Эти триТочки гарантируют, что производительность будет максимизирована и позволит сервисному уровню контролировать то, что выполняется в базе данных.

Надеюсь, это поможет.

0 голосов
/ 02 декабря 2010

Вы можете создать объект DataLoadOptions следующим образом:

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

Затем, когда вы выполняете запрос, он должен предварительно извлечь таблицу OrderStatus

...