如何将 ThenInclude 实现到 EF Core 自定义规范中?

hdo*_*itc 3 c# entity-framework-core

EF Core 3.1 我看过规范示例,并且想要实现 ThenInclude 模式。

public static class QuerySpecificationExtensions
{
    public static IQueryable<T> Specify<T>(this IQueryable<T> query, ISpecification<T> spec) where T : class
    {
        // fetch a Queryable that includes all expression-based includes
        var queryableResultWithIncludes = spec.Includes
            .Aggregate(query,
                (current, include) => current.Include(include));

        // modify the IQueryable to include any string-based include statements
        var secondaryResult = spec.IncludeStrings
            .Aggregate(queryableResultWithIncludes,
                (current, include) => current.Include(include));

        // return the result of the query using the specification's criteria expression
        return secondaryResult.Where(spec.Criteria);
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以将其添加到字符串中,例如“User.UserRole.Role”,但我想实现对象。也许那里不可能?

Iva*_*oev 9

Includes上述成员ISpecification<T>被宣布为

List<Expression<Func<T, object>>> Includes { get; }
Run Code Online (Sandbox Code Playgroud)

The problem is that EF Core Include / ThenInclude chain cannot be represented with Expression<Func<T, object>>. This pattern was used in EF6 which supported a special syntax (Select) inside the include expression to resolve collection element. But EF Core does not support that out of the box.

The easiest and most natural way to plug EF Core pattern is to change the definition as follows:

List<Func<IQueryable<T>, IIncludableQueryable<T, object>>> Includes { get; }
Run Code Online (Sandbox Code Playgroud)

Adding the sample for entity having User property having UserRoles collection having Role property would be like this:

Includes.Add(q => q.Include(e => e.User).ThenInclude(e => e.UserRoles).ThenInclude(e => e.Role));
Run Code Online (Sandbox Code Playgroud)

And the corresponding part of the Specify method implementation would be:

var queryableResultWithIncludes = spec.Includes
    .Aggregate(query,
        (current, include) => include(current));
Run Code Online (Sandbox Code Playgroud)