Подтвердить что ты не робот

Внутренняя ошибка поставщика данных .NET Framework 1025

IQueryable<Organization> query = context.Organizations;

Func<Reservation, bool> predicate = r => !r.IsDeleted;

query.Select(o => new { 
    Reservations = o.Reservations.Where(predicate)
}).ToList();

этот запрос выдает исключение "Ошибка поставщика данных в среде .NET Framework 1025", но ниже этого запроса нет.

query.Select(o => new { 
    Reservations = o.Reservations.Where( r => !r.IsDeleted)
}).ToList();

Мне нужно использовать первый, потому что мне нужно проверить несколько операторов if для построения правильного предиката. Я знаю, что я не могу использовать инструкции if в этом случае, поэтому я передаю делегат как параметр.

Как я могу выполнить первый запрос?

4b9b3361

Ответ 1

В то время как приведенные выше ответы верны, обратите внимание, что при попытке использовать его после оператора select нужно явно вызывать AsQueryable(), иначе компилятор предположит, что мы пытаемся использовать методы IEnumerable, которые ожидают, что Func и не Expression<Func>.

Вероятно, это была проблема с оригинальным плакатом, так как в противном случае компилятор будет жаловаться большую часть времени, когда он ищет Expression<Func>, а не Func.

Демо: Не удалось выполнить следующее:

MyContext.MySet.Where(m => 
      m.SubCollection.Select(s => s.SubItem).Any(expr))
         .Load()

Пока будет работать следующее:

MyContext.MySet.Where(m => 
      m.SubCollection.Select(s => s.SubItem).AsQueryable().Any(expr))
         .Load()

Ответ 2

После создания баунти (крысы!), я нашел этот ответ, который решил мою проблему. (Моя проблема связана с вызовом .Any(), который немного сложнее, чем этот вопрос...)

Короче говоря, вот ваш ответ:

IQueryable<Organization> query = context.Organizations;

Expression<Func<Reservation, bool>> expr = r => !r.IsDeleted;

query.Select(o => new { Reservations = o.Reservations.Where(expr) })
  .ToList();

Прочитайте указанный ответ для объяснения, почему вам нужна локальная переменная expr, и вы не можете напрямую ссылаться на другой метод возвращаемого типа Expression<Func<Reservation, bool>>.

Ответ 3

Спасибо, что рассмеялся. В конце концов, я был на правильном пути.

Во всяком случае, повторять, LINQ to Entities (спасибо Jon Skeet за то, что вы исправили меня, когда меня перепутали в моем собственном мыслительном процессе в комментариях) работает на Деревья выражений; он позволяет проектировать для преобразования лямбда-выражения в SQL с помощью QueryProvider.

Обычный Func<> хорошо работает для LINQ to Objects.

Итак, в этом случае, когда вы используете Entity Framework, любой предикат, переданный EF IQueryable, должен быть Expression<Func<>>.

Ответ 4

Я просто испытал эту проблему в другом сценарии.

У меня есть статический класс, полный предикатов Expression, которые я могу затем объединить или передать в EF-запрос. Один из них:

    public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
        IEnumerable<EventEnums.AttendeeStatus> statuses)
    {
        return ce => ce.Event.AttendeeStatuses
            .Where(a => a.ClientId == ce.Client.Id)
            .Select(a => a.Status.Value)
            .Any(statuses.Contains);
    }

Это вызвало ошибку 1025 из-за группового вызова метода Contains. Структура сущности ожидала выражения и обнаружила группу методов, которая привела к ошибке. Преобразование кода для использования лямбда (который может быть неявно применено к выражению) исправил ошибку

    public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
        IEnumerable<EventEnums.AttendeeStatus> statuses)
    {
        return ce => ce.Event.AttendeeStatuses
            .Where(a => a.ClientId == ce.Client.Id)
            .Select(a => a.Status.Value)
            .Any(x => statuses.Contains(x));
    }

Кроме того, я затем упростил выражение до ce => ce.Event.AttendeeStatuses.Any(a => a.ClientId == ce.Client.Id && statuses.Contains(a.Status.Value));

Ответ 5

Была аналогичная проблема. Библиотека ViewModels, которая выглядит так:

public class TagViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static Expression<Func<SiteTag, TagViewModel>> Select = t => new TagViewModel
    {
        Id = t.Id,
        Name = t.Name,
    };

Это работает:

var tags = await db.Tags.Take(10).Select(TagViewModel.Select)
    .ToArrayAsync();

Но это не скомпилируется:

var post = await db.Posts.Take(10)
    .Select(p => new {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).Select(TagViewModel.Select)
    })
    .ToArrayAsync();

Потому что второй .Select является беспорядок - первый из них действительно вызывается из ICollection, который не является IQueryable, поэтому он потребляет это первое выражение как простой Func, а не Expression<Func.... Это возвращает IEnumerable<..., как описано на этой странице. Итак .AsQueryable() на помощь:

var post = await db.Posts.Take(10)
    .Select(p => new {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
            .Select(TagViewModel.Select)
    })
    .ToArrayAsync();

Но это создает новую, более сложную проблему: либо я получаю Internal Framework... Ошибка 1025, либо получаю переменную post с полностью загруженным свойством .Post, но свойство .Tags имеет объект прокси EF, который кажется, используется для Lazy-Loading.

Решение состоит в том, чтобы управлять возвращаемым типом тегов, заканчивая использование класса Anonymous:

public class PostViewModel
{
    public Post Post { get; set; }
    public IEnumerable<TagViewModel> Tags { get; set; }

Теперь выберите это, и все это работает:

var post = await db.Posts.Take(10)
    .Select(p => new PostViewModel {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
            .Select(TagViewModel.Select)
    })
    .ToArrayAsync();