C# 使用LoadWith的“深度加载”
我有一个表结构,每个表都有一个名为ID的主键字段和与其父表的主键匹配的外键名称。因此,下表的主键出现在另一个表中,并且任何表中的第一个字段都是其主键:C# 使用LoadWith的“深度加载”,c#,sql,linq,C#,Sql,Linq,我有一个表结构,每个表都有一个名为ID的主键字段和与其父表的主键匹配的外键名称。因此,下表的主键出现在另一个表中,并且任何表中的第一个字段都是其主键: Category -------- CategoryID Title CategoryList ------------ CategoryListID CategoryID ListID List ---- ListID Title DataPoint --------- DataPointID RecordedDateTime
Category
--------
CategoryID
Title
CategoryList
------------
CategoryListID
CategoryID
ListID
List
----
ListID
Title
DataPoint
---------
DataPointID
RecordedDateTime
DataPointValue
--------------
DataPointValueID
DataPointID
TheValue
以上是通过CategoryList在Category和List之间进行的多对多连接。它也是从列表到数据点、数据点到数据点值的一对多连接
使用C/LINQ并给出CategoryID值列表,我想检索:
所有附加到类别的列表条目我都有ID。对于这些列表条目,我想采用最新的1个数据点,按RecordedDateTime降序排列。从那里,我想检索附加到数据点的每个数据点值
我的LINQ是:
DBDataContext上下文=新的DBDataContextConnectionString
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查询来检索这个公认的大量数据吗
非常感谢,
马特。你一个月前问过这个问题,但这里有一个答案 这里有几个问题: 在上下文上设置LoadOptions属性后,就无法更改它。您应该创建和配置DataLoadOptions对象,完成后,将其分配给上下文 LoadWith指定与父级一起自动加载的子级。因此loadOptions.LoadWithp=>p.DataPointValues将自动加载DataPoint的子级,而不是等到DataPoint.DataPointValues或任何您命名的属性被访问。LoadWith使加载成为非惰性的 AssociateWith允许您在自动加载关系的子项中筛选和排序。例如loadOptions.AssociateWithp=>p.DataPointValues.OrderByDowneringV=>v。该值将按值对DataPointValue进行排序 最后,我可能会将您的查询分为两部分,以便简化
// 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();