[英]Efficient Way To Query Nested Data
我需要从表中选择一些“主”行,并为每个结果返回另一个表中的许多详细信息行。 在没有多个查询的情况下实现此目的的好方法是什么(一个用于主行,一个用于获取详细信息行)。
例如,使用如下的数据库结构:
MasterTable:
- MasterId BIGINT
- Name NVARCHAR(100)
DetailTable:
- DetailId BIGINT
- MasterId BIGINT
- Amount MONEY
我如何最有效地填充下面的data
对象?
IList<MasterDetail> data;
public class Master
{
private readonly List<Detail> _details = new List<Detail>();
public long MasterId
{
get; set;
}
public string Name
{
get; set;
}
public IList<Detail> Details
{
get
{
return _details;
}
}
}
public class Detail
{
public long DetailId
{
get; set;
}
public decimal Amount
{
get; set;
}
}
通常,我会选择两种网格方法 - 但是,您可能还想查看FOR XML - 将父/子数据整形为xml并从中加载它非常容易(在SQL Server 2005及更高版本中)那里。
SELECT parent.*,
(SELECT * FROM child
WHERE child.parentid = parent.id FOR XML PATH('child'), TYPE)
FROM parent
FOR XML PATH('parent')
另外 - LINQ-to-SQL支持这种类型的模型,但您需要提前告诉它您想要哪些数据。 通过DataLoadOptions.LoadWith :
// sample from MSDN
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Customer>(c => c.Orders);
db.LoadOptions = dlo;
var londonCustomers =
from cust in db.Customers
where cust.City == "London"
select cust;
foreach (var custObj in londonCustomers)
{
Console.WriteLine(custObj.CustomerID);
}
如果您不使用LoadWith
,您将获得n + 1个查询 - 每个主行一个主服务器和一个子服务器列表。
可以使用以下单个查询完成:
select MasterTable.MasterId,
MasterTable.Name,
DetailTable.DetailId,
DetailTable.Amount
from MasterTable
inner join
DetailTable
on MasterTable.MasterId = DetailTable.MasterId
order by MasterTable.MasterId
然后在psuedo代码中
foreach(row in result)
{
if (row.MasterId != currentMaster.MasterId)
{
list.Add(currentMaster);
currentMaster = new Master { MasterId = row.MasterId, Name = row.Name };
}
currentMaster.Details.Add(new Detail { DetailId = row.DetailId, Amount = row.Amount});
}
list.Add(currentMaster);
有一些优势可以解决,但它应该给你一般的想法。
从master中选择<columns>
从主M选择<columns>在M.Id = C.MasterID上加入子C
您可以使用两个查询并在每个结果集上传递一个:
查询由MasterId排序的所有主数据,然后查询由MasterId排序的所有详细信息。 然后,使用两个嵌套循环,迭代主数据并在主循环中创建一个新的主对象foreach行,并在它们具有与当前主对象相同的MasterId时迭代细节,并在嵌套循环中填充其_details集合。
根据数据集的大小,您可以使用两个查询(一个用于所有主数据,一个用于所有嵌套数据)将所有数据提取到内存中的应用程序中,然后使用它以编程方式为每个对象创建子列表喜欢:
List<Master> allMasters = GetAllMasters();
List<Detail> allDetail = getAllDetail();
foreach (Master m in allMasters)
m.Details.Add(allDetail.FindAll(delegate (Detail d) { return d.MasterId==m.MasterId });
通过这种方法,您实际上是为了速度来交换内存占用。 您可以轻松地对此进行调整,以便GetAllMasters
和GetAllDetail
仅返回您感兴趣的主要和详细项目。另请注意,为了使此有效,您需要将MasterId添加到详细信息类
这是您可能考虑的替代方案。 每个开发人员花费150美元,但时间也是金钱......
我们使用一个名为Entity Spaces的对象持久层,它为您生成完全符合您需要的代码,并且您可以在架构更改时重新生成。 使用数据填充对象是透明的。 使用上面描述的对象看起来像这样(原谅我的VB,但它也适用于C#):
Dim master as New BusinessObjects.Master
master.LoadByPrimaryKey(43)
Console.PrintLine(master.Name)
For Each detail as BusinessObjects.Detail in master.DetailCollectionByMasterId
Console.PrintLine(detail.Amount)
detail.Amount *= 1.15
End For
With master.DetailCollectionByMasterId.AddNew
.Amount = 13
End With
master.Save()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.