我有一个(由于契约(Contract)限制而设计的和过度简化的)数据模型,应该如下所示:
public class ProvisionalData
{
public int ProvisionalDataID { get; set; }
public string Data { get; set; }
public Lot Lot { get; set; }
}
public class Destination
{
public int DestinationID { get; set; }
public string Name { get; set; }
}
public class LotDestination
{
public int LotDestinationID { get; set; }
public int DestinationID { get; set; }
public DateTime Month { get; set; }
public Destination Destination { get; set; }
}
public class Lot
{
public int LotID { get; set; }
public int ProvisionalDataID { get; set; }
public int LotDestinationID { get; set; }
public ProvisionalData ProvisionalData { get; set; }
public LotDestination LotDestination { get; set; }
}
从 Lot 到 ProvisionalData 的关系是双方都需要的一对一关系。请注意,这不是整个模型,也不是关注的领域。问题在于配置一对一关系。
我与一对一映射流畅配置相关:
public class LotConfig : EntityTypeConfiguration<Lot>
{
public LotConfig()
{
ToTable("Lot");
HasKey(x => x.LotID);
HasRequired(x => x.ProvisionalData)
.WithRequiredDependent(x => x.Lot)
.WillCascadeOnDelete(true);
}
}
public class ProvisionalDataConfig : EntityTypeConfiguration<ProvisionalData>
{
public ProvisionalDataConfig()
{
ToTable("ProvisionalData");
HasKey(x => x.ProvisionalDataID);
}
}
显示的其他关系实际上已建立 - 我已验证它们是在我的上下文中配置的,并且所有 IDbSet 都存在并正常运行。事实上,除了导航属性上的某些 ProvisionalData 实体未由以下查询填充外,此设置的所有内容都“有效”:
var lotDestination = db.lotDestinations
.Where(x => x.DestinationId == destinationId && x.Month == month)
.Include(x => x.Lots)
.Include("Lots.ProvisionalData")
.Include(x => x.Destination)
.SingleOrDefault();
在我的真实数据集中,此查询将返回一个包含 30 个地 block 的目的地。其中 16 个已加载临时数据导航属性。 14 没有。当我手动循环遍历每个 Lot 和 db.Entry(lot).Reference(ProvisionalData).Load()
时,这个问题仍然存在。当我检查这些条目时,对于 .IsLoaded
,所有 30 个都返回 true
。查询和 .Includes
似乎在做它们应该做的事情,但由于我不明白的原因,一些实体没有回来。我希望它是一些我看不到的简单东西,因为我已经盯着它看了太久了。
但是,当我将关系(忽略现有数据库约束)更改为与 ProvisionalData 实体的一对多关系时,如下所示:
public class ProvisionalData
{
public int ProvisionalDataID { get; set; }
public string Data { get; set; }
public IList<Lot> Lots { get; set; }
}
和一个像这样的新 Lot 配置:
public class LotConfig : EntityTypeConfiguration<Lot>
{
public LotConfig()
{
ToTable("Lot");
HasKey(x => x.LotID);
HasRequired(x => x.ProvisionalData)
.WithMany(x => x.Lots)
.HasForeignKey(x => x.ProvisionalDataID);
}
}
一切正常。这里唯一的缺点是这没有反射(reflect)数据库中的真实约束,因此您可以在技术上尝试将多个 Lots 添加到同一 block ProvisionalData,这会在尝试保存时中断。我可以自己构建逻辑来防止这种情况发生,但为什么我不能在 Entity Framework 中表达它?我的配置不正确吗?
同样有趣的是,当我将上述查询切换到这个愚蠢的版本以进行测试时(EF 中仍然存在一对一映射):
var quota = db.Lots
.Where(l => l.LotDestination.DestinationID == destinationId && l.LotDestination.Month == m)
.Include(x => x.ProvisionalData)
.Include(x => x.LotDestination)
.Include(x => x.LotDestination.Destination)
.Select(x => x.LotDestination)
.FirstOrDefault();
所有临时数据都会返回,但某些目的地不会。这向我暗示,它与在一对一中包含多个深度的导航属性有关。以前有其他人经历过这种行为吗?
最佳答案
除共享主键 1:1 关联情况外,EF 不正式支持 1:1 关联。
您正在做的是创建 1:many's 并试图告诉 EF 它确实是 1:1。问题是,db 模式实际上是一个 1:many 模式,EF 会在这里出现问题。
如果你的要求是1:1,那么你需要使用共享主键(两个实体有相同的主键),一个也把它当作外键。
关于c# - 一对一关系不加载所有实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18006324/