I am having a bit of a nightmare figuring out the reason why the following combination of Include(...)
followed by Where(...)
doesn't yield the results expected:
- I am separating the items from the database into two parts via
Where(...)
. - The
Where(...)
conditions are mutually exclusive and complementary. - The
Where(...)
calls depend on a related object, hence I useInclude(...)
- I know for a fact that both parts contain elements.
Code:
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);
}
The output printed is:
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
With the exception of totalCount
:
The count for the partial queries using
ToList().Count
is wrong in both cases.The
IQueryable<T>
extension methods (CountAsync()
fromEntityFramework
andCount()
fromSystem.Core
) yield the same results in both cases.The count of items with a
MetadataFile
is correctThe count of items without a
MetadataFile
is incorrect
The count of items without a
MetadataFile
should be equal to 8372 - 7908 = 464, as verified in the database.
This suggests that there is something wrong with the way I am calling the Include()
extension method.
Is this due to the fact that I am enumerating the same queries multiple times and that I am keeping the same connection?
Is there some strange nature behind the scenes that I am not aware of and explains this seemingly-weird behaviour???
Please shed some light!!!
EF Model Details
This is how I am defining the entities and mappings:
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; }
...
}
and the mappings:
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);
In particular, this has the effect of defining a Optional:Required
relationship
FeedEntry 1 ←—→ 0..1 MetadataFile
where FeedEntry
is automatically the principal in the relationship and MetadataFile
the dependent.
So the question has been answered, and the explanation is all as described by the answer below and the fact that I was using the described model to target both a new database and an existing database.