Quantcast
Channel: ADO.NET, Entity Framework, LINQ to SQL, NHibernate
Viewing all articles
Browse latest Browse all 1698

EF Core 5 - Does the order of Include()/Where() methods in queries matter?

$
0
0

I am upgrading from .NET Core 2.2 to .NET 5.0 one major release at a time (2.2 -> 3.0 -> 3.1 -> 5.0), and I have a LINQ query into a MySQL database that works differently after the upgrade to 5.0. The query works fine in 2.2, 3.0, and 3.1, but after the upgrade to 5.0 one of the Include() calls does not seem to have any effect. The query is:

var adminClient = (this._context.AdminUserClients    .Include(f => f.Client)    .Where(f => f.User.Id == user.Id && f.Client.Id != 1)    .Include(f => f.Client.ClientUserRoles)  // This Include does not seem to have an effect    .ThenInclude(f => f.User)    .FirstOrDefault())?.Client;

(See below for the model.)

When this runs in EF Core 3.1 (2.2 and 3.0 are similar) it generates a SQL statement with two subqueries, one to joinAdminUserClients, AspNetUsers, and Clients, and one to joinClientUserRoles and AspNetUsers. Then, it joins the two subqueries to generate the result. In EF Core 5.0, the generated SQL statement does not referenceClientUserRoles--it is essentially just the first subquery in the 3.1 SQL statement.

If I modify the query to move the Where() call after the Include() calls, it works:

var adminClient = (this._context.AdminUserClients    .Include(f => f.Client)    .Include(f => f.Client.ClientUserRoles)  // This Include runs fine    .ThenInclude(f => f.User)    .Where(f => f.User.Id == user.Id && f.Client.Id != 1)    .FirstOrDefault())?.Client;

In this case, the generated SQL statement is virtually identical to the one generated in 3.1.

I am not sure why this makes a difference. Maybe the User object needs to be included before it is referenced in theWhere() method? But that doesn't make sense to me because (1) it works in 2.2, 3.0, and 3.1, and (2) my understanding is that the relative order of the Include() and Where() methods should not impact the return set (though I get that it can impact performance).

Questions

  1. Is there a problem with the ordering of the Include() and Where() methods in the original query?
  2. Is there a change from EF Core 3.1 to EF Core 5.0 that would cause the behavior of this query to change?

Note on Split Queries

Because I am upgrading from 2.2 to 5.0, I am using UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery) to emulate the 2.2 behavior. However, I have tested:

  1. Adding AsSplitQuery() to the query.
  2. Using UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery).
  3. Removing UseQuerySplittingBehavior() entirely.

In all of these cases, the behavior is the same.

Model

public class AdminUserClient
{    public long Id { get; set; }    [Required]    public ApplicationUser User { get; set; }    [Required]    public Client Client { get; set; }    [Required]    public DateTime CreatedOn { get; set; }
}

public class ApplicationUser : IdentityUser
{
    public UserNotificationsSetting NotificationSetting { get; set; }    [JsonIgnore]    public ClientUserRole ClientUserRole { get; set; }    public bool Locked { get; set; }    public string Name { get; set; }
}

public class Client
{
    public long Id { get; set; }    public string Name { get; set; }    public string Description { get; set; }    public bool RequireTwoFactor { get; set; }    public ApplicationUser CreatedBy { get; set; }    public DateTime CreatedOn { get; set; }    [JsonIgnore]    public ICollection<ClientUserRole> ClientUserRoles { get; set; }    public bool IsDeleted { get; set; }    public bool Locked { get; set; }
}

public class ClientUserRole
{
    public long Id { get; set; }    [Required]    public long ClientId { get; set; }    [JsonIgnore]    public Client Client { get; set; }    [Required]    public string UserId { get; set; }    public ApplicationUser User { get; set; }    [Required]    public ApplicationUser CreatedBy { get; set; }    [Required]    public DateTime CreatedOn { get; set; }    [Required]    [Column(TypeName = "nvarchar(15)")]    public UserRole Role { get; set; }
}

Viewing all articles
Browse latest Browse all 1698

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>