2010-08-20 2 views
1

У меня есть структура таблицы, каждая таблица с полем первичного ключа с именем «ID» и именами внешних ключей, соответствующими первичному ключу их родительской таблицы. Поэтому ниже таблицы имеют отношения, где их первичный ключ появляется в другой таблице и первое поле в любой таблице это первичный ключ:«Глубокая загрузка» с LoadWith

Category 
-------- 
CategoryID 
Title 


CategoryList 
------------ 
CategoryListID 
CategoryID 
ListID 


List 
---- 
ListID 
Title 


DataPoint 
--------- 
DataPointID 
RecordedDateTime 


DataPointValue 
-------------- 
DataPointValueID 
DataPointID 
TheValue 

Выше многие-ко-многим присоединиться между категорией и списком, с помощью CategoryList. Это также соединение «один ко многим» из списка в DataPoint, DataPoint в DataPointValue.

Использование C#/LINQ и дан список значений CategoryId, я хотел бы получить:

Все записи списка прикрепленных к категории I имеют идентификаторы для. С этими записями в списке я хотел бы взять последние данные DataPoint, как указано в RecordedDateTime Descending. Оттуда я хотел бы получить каждый DataPointValue, прикрепленный к DataPoint.

LINQ у меня есть:

DBDataContext контекст = новый DBDataContext (ConnectionString);

 context.LoadOptions = new DataLoadOptions(); 
     context.LoadOptions.LoadWith<DataPoint>(p => p.DataPoints.OrderByDescending(p.RecordedDataTime).FirstOrDefault()); 

     // this next line is how I get the list of category IDs, but don't worry about that... 
     List<int> categoryIDs = (from TreeNode n in nodes 
           select Int32.Parse(n.Value)).Distinct().ToList(); 

     var lists = from i in context.List 
             join ci in context.CategoryLists on i.ListID equals ci.ListID 
             join p in context.DataPoints on i.ListID equals p.ListID 
             join v in context.DataPointValues on p.DataPointID equals v.DataPointID 
             where categoryIDs.Contains(ci.CategoryID) 
             orderby i.Title ascending 
             select new 
             { 
              List = i, 
              DataPoint = p, 
              DataPointValues = p.DataPointValues 
             }; 

Но это, очевидно, не работает - LoadWith вызывает у меня проблемы. Может ли кто-нибудь объяснить, как построить LoadWith так, чтобы он вызывал как можно меньше SQL-запросов, чтобы получить этот (правда, большой) объем данных, пожалуйста?

Большое спасибо,

Matt.

ответ

3

Вы спрашивали об этом месяц назад, но вот ответ в любом случае ...

Есть несколько вопросов здесь:

  • После того, как вы установите свойство LoadOptions на контекст, вы можете» t изменить его. Вы должны создать и настроить свой объект DataLoadOptions, и когда вы закончите, назначьте его контексту.

  • LoadWith указывает, какие дети автоматически загружаются родителем. Таким образом, loadOptions.LoadWith<DataPoint>(p => p.DataPointValues) будет автоматически загружать дочерние объекты DataPoint и не дожидаться доступа к свойству DataPoint.DataPointValues ​​(или тому, что вы называете его). LoadWith делает загрузку не ленивой (нетерпеливой).

  • AssociateWith позволяет фильтровать и заказывать детям, которые автоматически загружают отношения. Например, loadOptions.AssociateWith<DataPoint>(p => p.DataPointValues.OrderByDescending(v => v.TheValue)) будет сортировать DataPointValues ​​по значению.

И, наконец, я бы, вероятно, разделил ваш запрос на два, чтобы упростить его.

// first setup a DataPoint -> DataPointValue relationship in your DBML 
// then set up the DataPointValues to automatically load with DataPoint: 

dataLoadOptions.LoadWith<DataPoint>(dp => dp.DataPointValues); 

// then assign the load options to the context here 

// First query 
List<int> listIDs = context.CategoryLists 
     .Where(cl => categoryIDs.Contains(cl.CategoryListID)) 
     .Select(cl => cl.ListID) 
     .ToList(); 


// Second query(ies) - this isn't the most elegant, but simple is usually better :) 
List<DataPoint> dataPoints = new List<DataPoint>(); 

foreach (int listID in listIDs) 
{ 
    DataPoint foundDP = context.DataPoints 
     .Where(dp => listIDs.Contains(dp.ListID)) 
     .OrderByDescending(dp => dp.RecordedDateTime) 
     .Take(1) 
     .SingleOrDefault(); 

     // Remember, at this point DataPointValues will already be loaded into the DataPoint 

    if (foundDP != null) 
     dataPoints.Add(foundDP); 
} 

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

EDIT:

К сожалению, начал думать об этом ...

Вы могли бы сделать это вместо (чище, быстрее):

loadOptions.LoadWith<List>(l => l.DataPoints); 
loadOptions.AssociateWith<List>(l => l.DataPoints.OrderByDescending(dp => dp.RecordedDateTime).Take(1)); 
loadOptions.LoadWith<DataPoint>(dp => dp.DataPointValues); 

// assign the LoadOptions here,  
// then: 

List<DataPoint> dataPoints = context.CategoryLists 
     .Where(cl => categoryIDs.Contains(cl.CategoryID)) 
     .Select(cl => cl.List.DataPoints) 
     .ToList(); 
Смежные вопросы