2010-08-20 39 views
1

我有一個表結構,每個表都有一個名爲「ID」的主鍵字段和與其父表的主鍵匹配的外鍵名。因此,表格下方有關係,他們的主鍵出現在另一個表和任何表中的第一場是它的主鍵:使用LoadWith「Deep loading」

Category 
-------- 
CategoryID 
Title 


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


List 
---- 
ListID 
Title 


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


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

上面是多到很多類別和清單之間的連接,通過所屬分類。它也是從List到DataPoint,DataPoint到DataPointValue的一對多連接。

使用C#/ LINQ和給出的類別ID值的列表,我想檢索:

所有連接到I類有ID的該列表條目。有了那些List條目,我想按照RecordedDateTime Descending命令來取最近的1個DataPoint。從那裏我想檢索連接到DataPoint的每個DataPointValue。

的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查詢來檢索這個(確實很大)的數據量嗎?

非常感謝,

馬特。

回答

3

你問這在一個月前,但這裏有一個答案反正...

這裏有幾個問題:

  • 一旦你設置的背景下LoadOptions屬性,你可以」不要改變它。您應該創建並配置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); 
} 

無論如何,這是一個長期的答案,你可能甚至可能不需要!嗯,我想這對我來說是一種習慣。希望能幫助到你。

編輯:

對不起,開始思考這個...

你可能做到這一點,而不是(清潔,更快):

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();