C# 实体框架-更新的关系不会检索从旧关系创建的数据
我最近更新了我的C# 实体框架-更新的关系不会检索从旧关系创建的数据,c#,entity-framework,sqlite,ef-code-first,C#,Entity Framework,Sqlite,Ef Code First,我最近更新了我的实体框架(版本6.2.0)映射,以提高应用程序的性能,但不修改数据库架构。基本上,我有一对多的关系,我变成了一对一的关系 当我使用这个新映射创建新对象时,一切都按预期进行:对象以外键列中的正确值保存在数据库中,等等。当我重新启动应用程序(并重置DbContext)并访问这些对象时,实体的导航属性就实现了 当我尝试访问在此EF映射更新之前创建的对象时,就会出现问题。对于这些旧对象,导航属性为null,我无法访问关系的另一端 具体来说,我有两个定义如下的表: ______
实体框架
(版本6.2.0)映射,以提高应用程序的性能,但不修改数据库架构。基本上,我有一对多的关系,我变成了一对一的关系
当我使用这个新映射创建新对象时,一切都按预期进行:对象以外键列中的正确值保存在数据库中,等等。当我重新启动应用程序(并重置DbContext)并访问这些对象时,实体的导航属性就实现了
当我尝试访问在此EF映射更新之前创建的对象时,就会出现问题。对于这些旧对象,导航属性为null,我无法访问关系的另一端
具体来说,我有两个定义如下的表:
______ _____________
|Sample| |Sample_Result|
|------| |-------------|
|Id |<--------|Result_Of |
|______| Fk |_____________|
SELECT *
FROM Sample s
INNER JOIN Sample_Result sr ON s.Id = sr.Result_Of;
Sample
SampleID (PK)
SampleResult
SampleResultID (PK)
SampleID (FK)
在我的dbContext中,我添加了以下映射:
modelBuilder.Entity<SampleResultEntity>()
.HasRequired(sr => sr.ResultOf)
.WithRequiredDependent(s => s.Result);
我不会“丢失”行(如果我有40个样本,我会得到40行)。所以外键设置得很好
有人能解释一下这种行为吗?您可能需要概述完整的表结构,因为根据您所描述的内容,您不能简单地根据模式将映射从1到多更改为1到1 一对多模式将如下所示:
______ _____________
|Sample| |Sample_Result|
|------| |-------------|
|Id |<--------|Result_Of |
|______| Fk |_____________|
SELECT *
FROM Sample s
INNER JOIN Sample_Result sr ON s.Id = sr.Result_Of;
Sample
SampleID (PK)
SampleResult
SampleResultID (PK)
SampleID (FK)
一对一架构将如下所示:
样品
样本ID(PK)
因此,在一个有效地包含1到1行的1对多模式中,SampleID=1,SampleResult的SampleResultID=16,SampleID=1。
如果您只是将映射更改为1对1,EF将期望两个表上的PK相等。由于SampleResult的主键是SampleResultId,因此不可能获得正确的记录,因为它将比较Sample.SampleId/w SampleResult.SampleResultId(不是SampleResult.SampleId)
您的新测试记录似乎有效,因为您可能会发现:
Sample.SampleID = **220**
SampleResult.SampleResultID = **220**
SampleResult.SampleID = 220
如果您对键使用标识(Int)列,那么这个问题的表现会有所不同,您可能会得到空链接,或者得到指向错误结果的链接。因为您使用的是guid,并且每个ID都是相对唯一的,所以结果将是空链接
我建议在测试数据库上使用探查器来捕获加载样本/结果对时使用的SQL,以验证是否加入了正确的列
在不更改模式的情况下,只要将SampleResult.SampleResultId设置为标识/默认值,并且您可以保证没有1对多实例(单个样本上的多个结果),您就应该能够更新EF中的映射,以将SampleResult上的SampleId视为键。这样,通过新映射,EF将2链接在一起。这意味着您以前的“新”测试记录将不再有效,因为它们将Sample.SampleID与SampleResult.SampleResultID相结合,但您的原始记录应该有效,新记录也应该有效。EF的键不必与表上的PK匹配,只要您首先使用DB(无迁移),并且满足模式。如果samplesultid的DB列默认为NewSequentialId()
或NewId()。如果PK是在代码中设置的,那么您可能需要将属性映射为常规列,并记下如何使用SampleId。如果您有任何其他实体基于SamplesUltId链接到SamplesUltd,则会“中断”。EF将在加入时将SampleId视为密钥
最后一点注意:我有点担心这样一个结论,即Sample和SampleResult之间的一对多关系会导致性能问题,这些问题可以通过重新映射到一对一来解决。虽然一对多的关系只包含一个子元素有点误导,但最终EF将在这两种情况下使用内部联接。我强烈怀疑还有别的事情在起作用。如果对新行使用NewId()
/GUID.New
,随着系统的增长,GUID键可能会出现问题。这是因为聚集索引中128位键的相对随机性会导致索引表中出现大量碎片。最好使用NewSequentialId()
或NewSequentialId()
的基于代码的实现来生成唯一但可排序的GUID,以最大限度地减少这种影响,并将其与数据库表上的定期索引维护相结合。听起来您的数据库架构好像是被更改了。