Skip to content

Query Filter: Inconsistent number of records returned with .ToList()/.Count() #36360

@Sniperhid

Description

@Sniperhid

Bug description

There appears to be an issue with resolving queries in the case that a query filter .HasQueryFilter() has been used. In the provided example calling .ToList() on query returns 1 record, and the .Count() returns 2 records.

I believe this is due to the foreign key being required and thus resolving to some kind of inner join that always expects a result. However the query filter means that an inner join is inappropriate.

I first came across this issue with SQL Server, and then produced a simple reproducible version in the attached code using the In Memory Database provider. I have tested this against version 9.0.7 of the packages.

In my real world use case I use these to drive a datagrid. Which I believe is fairly common. I would have also expected possibly rewriting the ParentName assignment might result in a different output:
ParentName = x.Parent != null ? x.Parent.Name : null
but it did not. I personally believe in my example the .ToList() should return both records, but the bigger issue is the inconsistency.

Your code

public class MyDbContext : DbContext
{
    public DbSet<Child> Children { get; set; }
    public DbSet<Parent> Parents { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseInMemoryDatabase("MyDatabase");
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Parent>().HasQueryFilter(x => !x.Deleted);
        modelBuilder.Entity<Child>().HasQueryFilter(x => !x.Deleted);

        base.OnModelCreating(modelBuilder);
    }
}

public class Child
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int ParentId { get; set; }
    public Parent Parent { get; set; }
    public bool Deleted { get; set; }
}
public class Parent
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Deleted { get; set; }
}

using var context = new MyDbContext();

// Add a new customer
context.Parents.Add(new Parent { Name = "Parent1" });
context.Parents.Add(new Parent { Name = "Parent2" });
context.SaveChanges();

context.Children.Add(new Child { Name = "Child1", ParentId = 1 });
context.Children.Add(new Child { Name = "Child2", ParentId = 2 });
context.SaveChanges();

var parent1 = context.Parents.Where(x => x.Id == 1).FirstOrDefault();
parent1.Deleted = true;
context.SaveChanges();


var query = context.Children.Select(x => new
{
    ChildName = x.Name,
    ParentName = x.Parent.Name
});

var data = query.ToList();
var count = query.Count();

Console.WriteLine($"Data: {data.Count} Count: {count}");
// OUTPUT: data.Count == 1
// OUTPUT: count == 2
// Note they are not the same(!)

Stack traces


Verbose output


EF Core version

9.0.7

Database provider

SqlServer and InMemoryProvider

Target framework

.NET 9.0

Operating system

Windows 11

IDE

Visual Studio 17.4

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy