Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 祖父母的外键应该存储在孙子表中吗?_Sql_Entity Framework_Database Design_Orm_Foreign Keys - Fatal编程技术网

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

Sql 祖父母的外键应该存储在孙子表中吗?,sql,entity-framework,database-design,orm,foreign-keys,Sql,Entity Framework,Database Design,Orm,Foreign Keys,在表中包含祖父母+外国键的好处和责任是什么 例如,如果我的对象模型如下所示。(大大简化了,因此它不适用于分层递归表。) 想到的两个数据模型选项是: 备选案文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更加规范化,插入

在表中包含祖父母+外国键的好处和责任是什么

例如,如果我的对象模型如下所示。(大大简化了,因此它不适用于分层递归表。)

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

备选案文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, ...}
EntityFramework4.0是否优雅地处理了这种情况?这两种选择的利弊是什么?还有另一个我应该考虑的选择吗?

或者更简单地说,一个人怎么会用谷歌搜索这种问题

另一个注意事项:和你们中的许多人一样,我必须坚定地向选项A倾斜,但我知道我读过一篇msdn文章,其中详细介绍了为什么选项B更好。不幸的是,我找不到它(


提前感谢您的想法。

如果您的数据库主要是OLTP,我会选择选项A。如果您的报告成为问题,您可以创建一个视图或非规范化表来表示选项B


如果您的数据库主要是OLAP,我会选择选项B。

我想说,如果DB对递归关系有很好的支持(即Oracle在这方面很出色,其他一些数据库对这些查询有特定的语法),那么就使用递归(您的选项A)。否则,您将被困在调试代码的几天中,以确保在关系更改时更新所有需要更新的记录,并且需要手动级联更改


对于谷歌来说,使用术语“递归表”或“递归查询”。

我会避免像瘟疫一样使用选项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
这是一个更复杂的选择吗?是的,但它不应该给任何人带来挑战,让他们弄清楚到底发生了什么

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

代码:

var entity = context.D.Where(d => d.Id == 4).First();
var grandParent = entity.C.B.A;
在查询中(使用LINQ和联接):

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


这顺便提到,复合键“比maange难多了”…虽然它看起来像一棵树,但这不是一个递归关系。虽然它仍然是一棵树,但树有一个定义的深度,到达每个级别的步骤都不同。同意,我认为它是一棵树。我不担心级联问题,因为我认为即使是access也能有效地处理这种情况。(我使用的是SQL 2008 R2)谢谢你的意见!-1.我看不出有任何合理的理由使用选项B。正确规范化版本(选项a)所增加的复杂性是微不足道的,选项B涉及的风险/坏业力很高。@Adam:我只建议在OLAP情况下使用选项B,在这种情况下,我希望数据库/数据仓库将以一定的间隔填充,并保持相对静态。
var entity = context.D.Where(d => d.Id == 4).First();
var grandParent = entity.C.B.A;
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();