efcore: OwnsMany cannot use HasQueryFilter

We are in the progress of trying to upgrading to use EF Core 2.2 And found that OwnsMany have some restriction.

Steps to reproduce

Example:

Models

public class User
{
    public Guid UserId { get; set; }
    public string Email { get; set; }
    public IEnumerable<Profile> Profiles { get; set; }
}
public class Profile
{
    public Guid ProfileId { get; set; }
    public string Email { get; set; }
    public bool IsActive { get; set; }
}

DbContext

protected override void OnModelCreating(ModelBuilder builder)
{
    #region User
    builder.Entity<User>(m =>
    {
        #region Mappings
        m.ToTable("User", "user");
        m.HasKey(x => x.UserId);

        m.OwnsMany(x => x.Profiles, b =>
        {
            b.HasForeignKey(p => p.Email);
            b.HasPrincipalKey(u => u.Email);
        });
        #endregion
    });

    builder.Entity<Profile>(m =>
    {
        #region Mappings
        m.ToTable("Profile", "user");
        m.HasKey(x => x.ProfileId);
        m.HasQueryFilter(x => x.IsActive);
        #endregion
    });
    #endregion
}

In this case, HasQueryFilter will work properly and only IsActive Profile being queried when I call this:

_dbContext.Set<User>().Include(u => u.Profiles)

However, when I want to simplify the OwnsMany relationship so no need to define Entity<Profile> specificly

This will not work

protected override void OnModelCreating(ModelBuilder builder)
{
    #region User
    builder.Entity<User>(m =>
    {
        #region Mappings
        m.ToTable("User", "user");
        m.HasKey(x => x.UserId);

        m.OwnsMany(x => x.Profiles, b =>
        {
            b.ToTable("Profile", "user");
            b.HasKey(x => x.ProfileId);
            b.HasQueryFilter(x => x.IsActive);
            b.HasForeignKey(p => p.Email);
            b.HasPrincipalKey(u => u.Email);
        });
        #endregion
    });
    #endregion
}

As CollectionOwnershipBuilder do not have HasQueryFilter

Further technical details

EF Core version: 2.2 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Windows 10 IDE: Visual Studio 2017 15.9.3

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 15 (8 by maintainers)

Most upvoted comments

In EF Core 5.0 I get this warning:

Warning: Entity 'Blog' has a global query filter defined and is the required end of a relationship
with the entity 'Post'. This may lead to unexpected results when the required entity is
filtered out. Either configure the navigation as optional, or define matching query filters for both entities
in the navigation. See https://go.microsoft.com/fwlink/?linkid=2131316 for more information.

If the configuration is like this:

modelBuilder.Entity<Blog>().HasMany(b => b.Posts).WithOne(p => p.Blog).IsRequired(false);
modelBuilder.Entity<Blog>().HasQueryFilter(b => b.Url.Contains("fish"));

… one solution is to add:

modelBuilder.Entity<Post>().HasQueryFilter(p => p.Blog.Url.Contains("fish"));

But if Blog owns Post I cannot use HasQueryFilter on Post.

After discussing this with @AndriySvyryd, and reading a bit online about this kind of scenario in the context of DDD, here are my thoughts:

  1. TL;DR: I don’t think we need to decide anything for 3.0 here, so adding propose-punt label.

  2. Aggregates that are too large as to need filtering are a smell. If we want ownership/aggregates to become a pit of success feature, an API that steers customers to design smaller aggregates may help.

  3. On the other hand, it is ok to have useful lower-level features that allow customers to do more advanced things, plus not all our customers want to necessary become DDD practitioners. Both rule-based eager loading and query filters are such low-level features.

  4. Precisely because query filters is one of those low-level feature for which it is ok to not always result on consistent behaviors (a well-know example of inconsistency happens when you load a dependent of a principal that has been filtered out: you get dependent with a dangling FK value, but no apparent principal object), I don’t want us to take a dogmatic position and say now that we never want to allow this. I prefer to wait for feedback.

  5. I think if we end up enabling query filters for owned objects and then that doesn’t work with document oriented database, that is still all right. It is just a consequence of restrictions in the query capabilities of the database (e.g. one full document at the time).