祖父母外键应该存储在孙子表中吗?

Dan*_*Eli 7 sql orm database-design entity-framework foreign-keys

在表格中包括祖父母+外围钥匙有什么好处和责任.

例如,如果我的对象模型如下所示.(非常简化,所以它不适用于层级递归表.)

a {aId, bCollection, ...}
b {bId, cCollection, ...}
c {cId, dCollection, ...}
d {dId}
Run Code Online (Sandbox Code Playgroud)

想到的两个数据模型选项是:

选项1:

a {pkA, ...}
b {pkB, fkA, ...}
c {pkC, fkB, ...}
d {pkD, fkC, ...}
Run Code Online (Sandbox Code Playgroud)

选项2:

a {pkA, ...}
b {pkB, fkA, ...}
c {pkC, fkB, fkA, ...}
d {pkD, fkC, fkB, fkA, ...}
Run Code Online (Sandbox Code Playgroud)

选项1更加规范化,插入和更新将更容易,但我可以看到查询变得非常复杂,特别是有很多关系和/或复合键.

选项2使插入和更新变得复杂,但提取报告将更容易.此外,数据库将更大,但我并不真正关心它,因为它无论如何都很小.

但与那些与ORM类实体框架相关的问题相比,这些问题相当微不足道.我倾向于选项2,因为我想直接从父母那里访问孙子,如下所示:

Class A { id, bCollection, cCollection, dCollection, ... }
Class B { id, cCollection, dCollection, ... }
Class C { id, dCollection, ... }
Class D { id, ...}
Run Code Online (Sandbox Code Playgroud)

实体框架4.0是否优雅地处理这种情况?这两种选择的优缺点是什么?我还应该考虑另一种选择吗?

或者更简单的说,一个人如何谷歌这个问题?!?

另外一个注意事项:像你们中的许多人一样,必须对选项A有很大的帮助,但我知道我已经阅读了一篇msdn文章,该文章详细介绍了为什么选项B更好.不幸的是,我找不到它.:(

提前感谢您的想法.

Ada*_*son 7

我会避免选择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
Run Code Online (Sandbox Code Playgroud)

选项B:

select a_id from d where id = @id
Run Code Online (Sandbox Code Playgroud)

选项A 复杂吗?是的,但它不应该成为任何人弄清楚正在发生什么的挑战.

至于与EF4的兼容性,这不是问题.您可以以线性方式向上导航父母链,以获得您想要的祖父母.您可以在代码或查询中执行此操作; 任何一个都可以正常工作:

在代码中:

var entity = context.D.Where(d => d.Id == 4).First();
var grandParent = entity.C.B.A;
Run Code Online (Sandbox Code Playgroud)

在查询中(使用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();
Run Code Online (Sandbox Code Playgroud)

在查询中(使用导航属性):

var grandparent = (from d in context.D
                  where d.Id == id
                  select d.C.B.A // or d.C.B.A.Id).First();
Run Code Online (Sandbox Code Playgroud)