[英]Strange behaviour using EF + LINQ: Include(…).Where(…)
我有点恶梦,想知道为什么下面的Include(...)
和Where(...)
不能产生预期结果的原因:
Where(...)
将数据库中的项目分为两部分。 Where(...)
条件是互斥和互补的。 Where(...)
调用取决于相关对象,因此我使用Include(...)
码:
using (var db = new FeedDbContext("My-Database-Connection"))
{
var queryWithout = db.FeedEntries
.Include(f => f.MetadataFile)
.Where(f => f.MetadataFile == null);
var queryWith = db.FeedEntries
.Include(f => f.MetadataFile)
.Where(f => f.MetadataFile != null);
//-- using ToList().Count
var totalCount = db.FeedEntries.ToList().Count;
var countWithout = queryWithout.ToList().Count;
var countWith = queryWith.ToList().Count;
Console.WriteLine("totalCount using ToList().Count: {0}", totalCount);
Console.WriteLine("countWithout using ToList().Count: {0}", countWithout);
Console.WriteLine("countWith using ToList().Count: {0}", countWith);
//-- using Count()
totalCount = db.FeedEntries.Count();
countWithout = queryWithout.Count();
countWith = queryWith.Count();
Console.WriteLine("totalCount using Count(): {0}", totalCount);
Console.WriteLine("countWithout using Count(): {0}", countWithout);
Console.WriteLine("countWith using Count(): {0}", countWith);
//-- using CountAsync()
totalCount = await db.FeedEntries.CountAsync();
countWithout = await queryWithout.CountAsync();
countWith = await queryWith.CountAsync();
Console.WriteLine("totalCount using CountAsync(): {0}", totalCount);
Console.WriteLine("countWithout using CountAsync(): {0}", countWithout);
Console.WriteLine("countWith using CountAsync(): {0}", countWith);
}
打印的输出为:
totalCount using ToList().Count: 8372
countWithout using ToList().Count: 8372
countWith using ToList().Count: 0
totalCount using Count(): 8372
countWithout using Count(): 8372
countWith using Count(): 7908
totalCount using CountAsync(): 8372
countWithout using CountAsync(): 8372
countWith using CountAsync(): 7908
除了totalCount
:
在两种情况下,使用ToList().Count
进行部分查询的ToList().Count
都是错误的。
在两种情况下, IQueryable<T>
扩展方法( EntityFramework
CountAsync()
和System.Core
Count()
)产生相同的结果。
项目以计数MetadataFile
是正确的
没有 MetadataFile
的项目计数不正确
如在数据库中验证的, 没有 MetadataFile
的项目数应等于8372-7908 = 464。
这表明我调用Include()
扩展方法的方式有问题。
这是由于我多次枚举相同的查询并且保持相同的连接吗?
幕后是否有一些我不知道的奇怪本质,并解释了这种看似奇怪的行为???
这就是我定义实体和映射的方式:
public partial class FeedEntry
{
public int Id { get; set; }
...
public virtual MetadataFile MetadataFile { get; set; }
public virtual ICollection<ImageFile> ImageFiles { get; set; }
public virtual ICollection<VideoFile> VideoFiles { get; set; }
...
}
public partial class MetadataFile : FileBase
{
...
public virtual FeedEntry FeedEntry { get; set; }
...
}
和映射:
modelBuilder.Entity<FeedEntry>()
.HasOptional(t => t.MetadataFile)
.WithRequired(t => t.FeedEntry);
modelBuilder.Entity<FeedEntry>()
.HasMany(t => t.ImageFiles)
.WithRequired(t => t.FeedEntry);
modelBuilder.Entity<FeedEntry>()
.HasMany(t => t.VideoFiles)
.WithRequired(t => t.FeedEntry);
特别是,这具有定义Optional:Required
关系的效果
FeedEntry 1 ←—→ 0..1 MetadataFile
其中, FeedEntry
自动是关系中的主体, MetadataFile
是依赖项。
因此,该问题已得到解答,其解释全如以下答案所述 ,事实是我正在使用所描述的模型同时针对新数据库和现有数据库。
实体框架不以这种方式支持1:1或1:0..1关系。 仅在存在公共共享主键时才支持它们。 这意味着两个表必须具有相同的主键名称,并且一个PK必须是另一个PK的外键(这也意味着至少一个PK不能是IDENTITY字段)
这样做的原因是EF不支持唯一约束,因此它不能保证外键字段中没有重复的ID。
从技术上讲,EF6.1支持唯一索引,但是它们尚未增强EF,以使其能够用于使1:1关系正常工作。
EF根本不支持这种映射,尽管它在某些情况下似乎可以使用,但您将遇到这种奇怪而怪异的行为,并且无法信任它。
ToList()方法不起作用,而其他方法起作用的原因是,ToList()方法实际上需要映射对象并检索它们。 这导致模型混乱。 尽管non-ToList()版本仅执行计数而没有实际映射任何对象(它仅生成sql并返回整数计数结果,所以不需要对象模型映射)。
尝试两件事,第一件事必须做EF如何加载数据。
我认为它认为由于延迟加载而不需要MetadataFile
,因此请关闭它,看看它是否有任何改变:
db.ContextOptions.LazyLoadingEnabled = false;
还请尝试使用成员.Include("MetadataFile").
的字符串文字.Include("MetadataFile").
这可能是关键。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.