来自DB的分层数据 – 加入或不加入

我试图为这个问题找到一个干净,高效的解决方案,但不知怎的。

琐事:
-ASP.Net C#应用程序(.Net 3.5)
-MS-SQL Server 2005

这是数据的样子:
类别 – >模板 – >实例

类别可以包含多个模板。
模板可以包含多个实例。

这三个中的每一个都有一个类,还有一个包含大量列的相应数据库表。

我想从数据库中将完整的类加载到C#Category类对象中,包括所有相关的模板和实例对象。

我现在有两个选择:
1) 在所有3个表上进行连接并一次读取所有数据。
好处 :数据库方面更快,一个查询中的所有信息。
缺点 :我传输了大量冗余数据,因为每一行中每个实例都有相同的类别和模板数据。

示例(简化):

CategoryID | CategoryName | TemplateID | TemplateName | InstanceID | InstanceName 1 | FirstCategory | 1 | FirstTemplate | 1 | FirstInstance 1 | FirstCategory | 1 | FirstTemplate | 2 | SecondInstance 1 | FirstCategory | 1 | FirstTemplate | 3 | ThirdInstance 1 | FirstCategory | 1 | SecondTemplate | 4 | FourthInstance 

2) 我自己查询每个表,首先收集类别数据,然后收集具有类别ID的相关模板数据,依此类推。
好处 :直观的aproach,在代码端更容易处理,没有提取冗余数据。
缺点 :对服务器的多个查询,可能更慢。

什么是最好的方式去这里? 我错过了一个选项吗?
解决方案1似乎有更好的性能,但它对我来说看起来“不洁净”。 我必须从一大堆数据行中获取一个类别的数据。

如果我选择解决方案1,这是获取类别和模板数据的最佳方式?
从第一个数据行读取它并在值更改后创建一个新实例?
做某种分组?

提前致谢! 这个问题让我头疼几天。

我正在使用Entity Framework来完成我目前正在做的项目。 在某些情况下对其进行分析时,它确实使用选项1并将表带回冗余数据。 因此,似乎微软选择了这种方法,并且他们拥有整个堆栈,因此可能知道如何对这个确切的问题做出正确的决定。

可能有一些启发式决定在某些情况下使用选项2,但我在我的分析中没有看到它。 此外,我还没有看到EF在单个查询中返回多个结果集。

假设:您正在使用ADO /存储过程,并且您具有规范化的数据结构。

您可以从一个存储过程调用返回3个结果集。

 1) select c.* from category c where c.id = @categoryId 2) select t.* from templates t join category c on t.categoryid = c.id where c.id = @categoryId 3) select i.* from Instance i join templates t on i.templateid = t.id join category c on t.categoryid = c.id where c.id = @categoryId 

并使用sqldatareader.read()和sqldatareader.Nextresult()通过sqldatareader顺序填充对象

它确实取决于您返回的数据的大小以及您是否经常请求此数据,无论您是使用基于集合的数据还是上述等。

还有第三种选择:在每个表上执行’select *’,然后在内存中进行连接。 您可以使用LINQ进行一些惰性评估:

  class Category { public int CategoryId { get; set; } public List 

编辑:您可以对模板/实例关系使用相同的逻辑:

  class Template { public int CategoryId { get; set; } public int TemplateId { get; set; } public List Instances { get { return Repository.Instances.Where(i => i.TemplateId == this.TemplateId).ToList(); } } } 

对于少量数据,选项1听起来不错,但是您应该更改类结构并为模板和实例执行组合,这意味着Template类应该具有Instance的集合,而Category将具有集合模板,您可以摆脱冗余数据。

如果数据很大并且您的网络带宽非常适合频繁进行数据库调用,则选项2是可预先设置的。

如果层次结构不是太深,并且每个级别上的子项数量相当小,我通常从选项#2开始。 您描述的直观方法。 它让我们可以使用我们已有的任何方法(getTemplates(),getInstances(234)等)。

但从性能角度来看,使用3表连接执行一个查询并按排序顺序处理记录可能是更快的选择(选项#1)。