在表格中包括祖父母+外围钥匙有什么好处和责任。
例如,如果我的对象模型如下所示。 (非常简化,所以它不适用于层级递归表。)
a {aId, bCollection, ...}
b {bId, cCollection, ...}
c {cId, dCollection, ...}
d {dId}
我想到的两个数据模型选项是:
选项1:
a {pkA, ...}
b {pkB, fkA, ...}
c {pkC, fkB, ...}
d {pkD, fkC, ...}
选项2:
a {pkA, ...}
b {pkB, fkA, ...}
c {pkC, fkB, fkA, ...}
d {pkD, fkC, fkB, fkA, ...}
选项1更加规范化,插入和更新将更容易,但我可以看到查询变得非常复杂,特别是有很多关系和/或复合键。
选项2使插入和更新变得复杂,但提取报告将更容易。此外,数据库会更大,但我并不关心它,因为它非常小。
但与ORM类似实体框架的问题相比,这些问题相当微不足道。我倾向于选项2因为我想直接从父母那里访问孙子,所以:
Class A { id, bCollection, cCollection, dCollection, ... }
Class B { id, cCollection, dCollection, ... }
Class C { id, dCollection, ... }
Class D { id, ...}
实体框架4.0是否优雅地处理这种情况?这两种选择的优缺点是什么?还有其他我应该考虑的选择吗?
或者更简单的说,一个人如何谷歌这个问题?!?
另外一个注意事项:像你们中的许多人一样,必须对选项A有很大的帮助,但我知道我已经阅读了一篇msdn文章,该文章详细介绍了为什么选项B更好。不幸的是,我找不到它。 :(
提前感谢您的想法。
答案 0 :(得分:6)
我会避免选择B像瘟疫一样。这两个选项的查询都不比另一个选项复杂得多,但第二个选项很多更难以维护,并且急于将选项A标准化。
对于查询选项A,您所谈论的只是添加简单连接。由于这不是一个递归关系,你必须已经预先知道查询可以“深入”多少级别,所以你不必担心它是脆弱的或只是为了一个潜在病例的子集。
比较您正在寻找深层嵌套节点的顶级父级的最深层案例:
选项A:
select
a.id
from d
join c on c.id = d.c_id
join b on b.id = c.b_id
join a on a.id = b.a_id
where d.id = @id
选项B:
select a_id from d where id = @id
选项A 更多是否复杂?是的,但它不应该对任何人弄清楚发生了什么是一个挑战。
至于与EF4的兼容性,这不是问题。您可以以线性方式向上导航父母链,以获得您想要的祖父母。您可以在代码或查询中执行此操作;任何一个都可以正常工作:
在代码中:
var entity = context.D.Where(d => d.Id == 4).First();
var grandParent = entity.C.B.A;
在查询中(使用LINQ和连接):
var grandparent = (from d in context.D
join c in context.C on d.CId == c.Id
join b in context.B on c.BId == b.Id
join a in context.A on b.AId == a.Id
where d.Id == id
select a // or a.Id).First();
在查询中(使用导航属性):
var grandparent = (from d in context.D
where d.Id == id
select d.C.B.A // or d.C.B.A.Id).First();
答案 1 :(得分:3)
如果您的数据库主要是OLTP,我会使用选项A.如果您的报告出现问题,您可以创建一个视图或非规范化表来表示选项B.
如果你的数据库主要是OLAP,我会选择B。
答案 2 :(得分:3)
我想说如果数据库对递归关系有很好的支持(即Oracle很擅长这个,其他几个都有这些查询的特定语法),那么使用递归(你的选项A)。否则,您将被困几天调试代码,确保在关系发生变化时更新需要更新的所有记录,并且需要手动级联您的更改。
对谷歌而言,使用术语“递归表”或“递归查询”。