Используйте PredicateBuilder в SelectMany LINQ to Entity Framework

Я впервые пишу здесь на stackoverflow.

Я хотел бы использовать PredicateBuilder в запросе LINQ с SelectMany.

я ввожу свой код

public async Task<List<Articolo>> OttieniElencoArticoliFiltratoComplessoAsync
    (ExpressionStarter<Articolo> predicateArticolo,
        ExpressionStarter<ArticoloFornitore> predicateFornitore,
        ExpressionStarter<Categoria> predicateCategoria,
        ExpressionStarter<Magazzino> predicateMagazzino,
        ExpressionStarter<PrezzoVendita> predicatePrezzoVendita)
    {
        using (var database = DatabaseContext.NuovoDatabase())
        {
            var query = database.Articoli.AsExpandable();

            if (predicateArticolo != null)
            {
                query = query.Where(predicateArticolo);
            }

            if (predicateFornitore != null)
            {
                query = query.AsExpandable().SelectMany(a => a.ElencoArticoliFornitore.Where(predicateFornitore)).Select(fornitore => fornitore.Articolo);
            }

            if (predicateMagazzino != null)
            {
                query = query.AsExpandable()
                    .SelectMany(articolo => articolo.ElencoMagazzino.Where(predicateMagazzino))
                    .Select(magazzino => magazzino.Articolo);
            }

            if (predicatePrezzoVendita != null)
            {
                query = query.AsExpandable().SelectMany(articolo =>
                    articolo.ElencoPrezzoVendita.Where(predicatePrezzoVendita).Select(vendita => vendita.Articolo));
            }

            if (predicateCategoria != null)
            {
                query = query.AsExpandable()
                    .SelectMany(articolo => articolo.ElencoCategorie.Where(predicateCategoria))
                    .Select(categoria => categoria.Articolo);
            }

            return await query.ToListAsync();
        }
    }

Я создаю предикат следующим образом

        private ExpressionStarter<ArticoloFornitore> PredicateFornitore()
    {
        var ritornaNull = true;
        var predicate = PredicateBuilder.New<ArticoloFornitore>();
        if (IsEnabledFiltroFornitore && FornitoreSelezionato != null)
        {
            ritornaNull = false;
            predicate = predicate.And(fornitore => fornitore.IdFornitore == FornitoreSelezionato.IdFornitore);
        }
        return ritornaNull ? null : predicate;
    }

    private ExpressionStarter<Categoria> PredicateCategoria()
    {
        var ritornaNull = true;
        var predicate = PredicateBuilder.New<Categoria>();
        if (IsEnabledCategoriaLivello1 && CategoriaLivello1Selezionata != null)
        {
            ritornaNull = false;
            predicate = predicate.And(categoria =>
                categoria.IdCategoriaLv1 == CategoriaLivello1Selezionata.IdCategoriaLv1);
        }

        if (IsEnabledCategoriaLivello2 && CategoriaLivello2Selezionata != null)
        {
            ritornaNull = false;
            predicate = predicate.And(categoria =>
                categoria.IdCategoriaLv2 == CategoriaLivello2Selezionata.IdCategoriaLv2);
        }

        if (IsEnabledCategoriaLivello3 && CategoriaLivello3Selezionata != null)
        {
            ritornaNull = false;
            predicate = predicate.And(categoria =>
                categoria.IdCategoriaLv3 == CategoriaLivello3Selezionata.IdCategoriaLv3);
        }

        if (IsEnabledCategoriaLivello4 && CategoriaLivello4Selezionata != null)
        {
            ritornaNull = false;
            predicate = predicate.And(categoria =>
                categoria.IdCategoriaLv4 == CategoriaLivello4Selezionata.IdCategoriaLv4);
        }

        if (IsEnabledCategoriaLivello5 && CategoriaLivello5Selezionata != null)
        {
            ritornaNull = false;
            predicate = predicate.And(categoria =>
                categoria.IdCategoriaLv5 == CategoriaLivello5Selezionata.IdCategoriaLv5);
        }
        return ritornaNull ? null : predicate;
    }

Я попробовал этот метод на LINQPAD с фиксированными данными вместо PredicateBuilder, и запрос работает. Но с PredicateBuilder я получаю ошибку 1025 поставщика данных .NET Framework.

Как я могу решить? Я хотел бы иметь возможность создать динамический запрос, который берет параметры из интерфейса и возвращает результаты.

Я надеюсь, что вы можете мне помочь.


person Antonio Pisarra    schedule 16.03.2018    source источник
comment
Вы забыли включить код, который использует PredicateBuilder.   -  person Evk    schedule 16.03.2018
comment
Я изменил сообщение и добавил код для создания предиката   -  person Antonio Pisarra    schedule 16.03.2018
comment
См. stackoverflow.com/questions/46706255/. Я бы предложил использовать Expression<Func<T, bool>>, а не ExpressionStarter<T>   -  person Ivan Stoev    schedule 16.03.2018


Ответы (1)


EntityFramework требует, чтобы ваши предикаты были Expression<Func<T, bool>>, а не Func<T, bool>. Это то, что делает IQueryable.ToExpandable(). Однако ваши объекты Entity, такие как articolo.ElencoPrezzoVendita, являются виртуальными объектами ICollection, поэтому предикат сокращается до Func<T, bool>, что несовместимо с EF.

Это не совсем слетает с языка, но вы можете попробовать что-то подобное (я не знал структуры ваших объектов) с базой данных, чтобы убедиться, что Expression используется.

if (predicatePrezzoVendita != null)
{
    query = query.AsExpandable()
        .SelectMany(articolo =>
            database.ElencoPrezzoVendita
                .Where(x => articolo.ForeignKeyID == x.ID)
                .AsExpandable()
                .Where(predicatePrezzoVendita)
                .Select(vendita => vendita.Articolo));
}
person Jono    schedule 16.03.2018
comment
Большое спасибо, я решил свою проблему с этим подходом. - person Antonio Pisarra; 16.03.2018