EF学习笔记5:怎样避免关系跨度

背景与动机 在上一篇博文EF行话中,我介绍了关系跨度(Relationship Span)的概念。 如果你记得关系跨度仅仅是对实体中缺少外键属性的一种补偿。 一个实体的关系跨度,让我们以StaffMember为例,可以确保Entity Framework知道与StaffMember有0..1关系的其它实体的键(EntityKey)(如DisciplineHistory)。 这些键很重要,没有它们Entity Framework不知道怎么删除或更新StaffMember(见提示7与提示9,有更多关于此概念的信息)。 目前通常0..1类型的关系是通过在数据库中由StaffMember表指向目标DisciplineHistory表的外键的外键来确立的。 在这种情况下关系跨度可以很容易的取得DisciplineHistory的键,因为我们可以进行"联合消除"。 虽然没有两个数据库完全一样,且完全有可能以完全不同的方式对相同的关系进行建模:你可以将FK放置在DisciplineHistorty表中。 一种实现这个目的的方法是使相关的DisciplineHistory表的PK与StaffMember的PK相同,换言之,PK即FK。事实上在数据库限制设计为1对0..1关系的情况下,这是EF支持的唯一方法。 这种方式最普遍用于对数据库建模时给实体添加额外的"方面"的情况。 在这些场合下,关系跨度开销有点偏大,因为Entity Framework不足以智能到知道怎么进行联合消除或这本就不可能(两个情况都是可能的)。 如果你更进一步推断这种情况,如有多个通过0..1关系关联的实体存在(例如StaffMember有许多如SalaryHistory,DisciplineHistory,AuditLog与BIO等),这时你会很容易发现,对StaffMember表进行一个简单查询的开销也将很大,这完全由于完成关系跨度操作的开销。 问题很明显… 怎样做来避免关系跨度? 这非常非常简单,你仅需要进行非跟踪(non-tracking)查询: var source = ctx.Staff; source.MergeOption == MergeOption.NoTracking; var staff = (from s in source where s.ID == 12 select s).First(); 这样结果查询将不会"跨越"所有关联表如SalaryHistory,DisciplineHistory等中的信息。 不幸的是结果也不会"存在于"ctx(上下文)中。所以如果你打算使用这个结果,你不得不在手动附加一次。 在.NET 4.0中对这个问题有一种变通方法,称为FK联合,如果你使用FK联合代替独立联合则根本无需进行关系跨度。 对于一个短暂的上下文这很少引起问题,但是对于一个持续的上下文你必须小心同一个实体(担不是同一个对象)已经不再是上下文中之前查询所得到的结果了。同样如果你想要更新这个实体,你不能简单的使用这个实体来建立新的关系,而是要首先获取所有关联的实体的所有PK。

你可能感兴趣的:(学习笔记)