Проблемы EF Core 3 с .Include () при использовании .AsExpandable () - PullRequest
1 голос
/ 05 августа 2020

Я перенес концепции из пары фреймворков CQRS, которые я видел, и только что столкнулся с некоторыми проблемами. домена приложения, скорее я предоставляю интерфейсы, IReadEntities и IWriteEntities, которые имеют такие методы, как Query () и Get (), которые за кулисами вызывают Set (), возвращая DbSet (), а затем позволяя связывать стандартные выражения LINQ, как для любых EF запрос. У меня проблемы с использованием Include () в моих IQueryables, поскольку я использую LinqKit с AsExpandable () в конце всех своих вызовов. Вот как выглядят мои методы контекстного запроса.

public new IQueryable<TEntity> Query<TEntity>() where TEntity : class, IEntity
{
    // AsNoTracking returns entities that are not attached to the DbContext
    return QueryUnfiltered<TEntity>().Where(_recordAuthority.Clause<TEntity>());
}

public IQueryable<TEntity> QueryUnfiltered<TEntity>() where TEntity : class, IEntity
{
    // AsNoTracking returns entities that are not attached to the DbContext
    return Set<TEntity>().AsNoTracking().AsExpandable();
}

Типичный обработчик запросов выглядит следующим образом:

public async Task<IEnumerable<GetCustomerView>> Handle(CustomersBy query, CancellationToken cancellationToken)
{
    var customers = _db.Query<Customer>();

    // Apply filters
    if (!string.IsNullOrEmpty(query.FirstName))
        customers = customers.Where(x => x.FirstName.Contains(query.FirstName));

    if (!string.IsNullOrEmpty(query.LastName))
        customers = customers.Where(x => x.LastName.Contains(query.LastName));

    // Execute the query and return the results
    var view = await customers.Select(x => new GetCustomerView
    {
        Id = x.Id,
        FirstName = x.FirstName,
        LastName = x.LastName,
        EmailAddress = x.EmailAddress
    }).ToListAsync(cancellationToken).ConfigureAwait(false) as IEnumerable<GetCustomerView>;

    return view;
}

Этот сценарий отлично работает, если я хочу получить информацию об адресе из связанной таблицы поскольку я использую проекцию на сервере базы данных, учитывая, что я использую Select перед выполнением. Есть сценарий ios, хотя имеет смысл вернуть граф объекта и указать операторы Include (...), но в его нынешнем виде указание _db.Query<Customer>().Include(c => c.Address) не гидратирует свойство навигации по адресу. Я попытался отключить AsExpandable (), а затем результаты вернутся.

Вопрос в том, видит ли кто-нибудь способ разрешить предоставление операторов Include, возможно, в качестве параметра метода, а затем я l oop через них и прикрепить их перед вызовом AsExpandable ()? Я не могу понять, как это сделать, если это возможно.

Может быть, есть другой подход?

Интересно, что это, по-видимому, отлично работает с версией этого шаблона, которую использует коллега, где они используют EF 6. Он говорит, что они без проблем указывают Include после AsExpandable.

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Это известная проблема с EF Core и LinqKit AsExpandable (и вообще с любой библиотекой расширений, которая использует пользовательский IQueryProvider для выполнения предварительной обработки дерева выражений запроса, например LinqKit), поскольку EF Core игнорирует все спецификации EF Core c IQueryable расширения (Include / ThenInclude, AsNoTracking et c.) Если поставщик запроса отличается (или не наследует) от EF Core (EF6 не имеет таких требований).

С учетом сказанного, в настоящее время нет другого решения, кроме применения всех спецификаций EF Core c расширений перед вызовом AsExpandable.

0 голосов
/ 05 августа 2020

Хорошо, это работает. Я создал перегрузку:

public IQueryable<TEntity> Query<TEntity, TProperty>(IEnumerable<Expression<Func<TEntity, TProperty>>> includes) where TEntity : class, IEntity
{
    var query = Set<TEntity>().AsNoTracking();

    foreach (var expression in includes)
    {
        query = query.Include(expression);
    }

    return query.AsExpandable();
}

Из своего обработчика я создаю список включаемых выражений и перехожу к запросу:

var includes = new List<Expression<Func<Customer, object>>>
{
    c => c.Address
};

var customers = _db.Query(includes);
var result = await customers.ToListAsync(cancellationToken).ConfigureAwait(false);

При выполнении запроса заполнено свойство навигации: введите описание изображения здесь

Означает, что я не «бегло» связываю их с точки зрения клиентского кода, но я не думаю, что это ужасно.

Мысли?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...