Невозможно создать постоянное значение типа. В этом контексте поддерживаются только примитивные типы или типы перечисления.

164

Я получаю эту ошибку по запросу ниже

Невозможно создать постоянное значение типа API.Models.PersonProtocol. В этом контексте поддерживаются только примитивные типы или типы перечисления

ppCombinedниже находится IEnumerableобъект PersonProtocolType, который состоит из двух PersonProtocolсписков.

Почему это не удается? Разве мы не можем использовать JOINпредложение LINQ внутри SELECTa JOIN?

var persons = db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
        new PersonDTO
        {
            personId = y.personId,
            addressId = y.addressId,                   
            favoriteId = x.favoriteId,
            personProtocol = (ICollection<PersonProtocol>) ppCombined
                .Where(a => a.personId == x.personId)
                .Select( b => new PersonProtocol()
                 {
                     personProtocolId = b.personProtocolId,
                     activateDt = b.activateDt,
                     personId = b.personId
                 })
        });
user2515186
источник

Ответы:

232

Это не может работать, потому что ppCombinedэто набор объектов в памяти, и вы не можете объединить набор данных в базе данных с другим набором данных, который находится в памяти. Вы можете попробовать вместо того, чтобы извлечь отфильтрованные элементы personProtocolна ppCombinedколлекции в памяти после того, как вы извлекли другие свойства из базы данных:

var persons = db.Favorites
    .Where(f => f.userId == userId)
    .Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
        new // anonymous object
        {
            personId = p.personId,
            addressId = p.addressId,   
            favoriteId = f.favoriteId,
        })
    .AsEnumerable() // database query ends here, the rest is a query in memory
    .Select(x =>
        new PersonDTO
        {
            personId = x.personId,
            addressId = x.addressId,   
            favoriteId = x.favoriteId,
            personProtocol = ppCombined
                .Where(p => p.personId == x.personId)
                .Select(p => new PersonProtocol
                {
                    personProtocolId = p.personProtocolId,
                    activateDt = p.activateDt,
                    personId = p.personId
                })
                .ToList()
        });
Slauma
источник
10
Ключевой частью для меня было добавление .AsEnumerable () // запрос к базе данных заканчивается здесь, остальное - запрос в памяти
Sameer Alibhai
2
@Slauma Так что, если я беспокоюсь о производительности, я должен избегать этого, так как он сначала загрузит все данные в память, а затем запросит их. Должен ли я написать сырой sql для этого сценария?
Арванд
Кажется, у @Arvand есть замечательный смысл. Если перед фильтром имеется большое количество записей, это может привести к значительному уменьшению объема доступных ресурсов памяти.
spadelives
5
@Slauma «Это не может работать, потому что ppCombined представляет собой набор объектов в памяти, и вы не можете объединить набор данных в базе данных с другим набором данных, который находится в памяти». Где я могу найти документацию о таких вещах? Мне действительно не хватает знаний об ограничениях EF, и когда я пытаюсь ограничить результирующий набор запросов, как этот, эта некомпетентность становится очень очевидной и замедляет меня.
Номенатор
1
Хорошая информация Я добавляю это исключение в свой список наименее интуитивных сообщений об исключениях. Это имеет смысл только после того, как вы поймете, почему это происходит.
ДВК
2

Не знаю, если кто-то ищет это. У меня такая же проблема. Выборка по запросу, а затем выполнение where (или join) и использование переменной select решили проблему для меня. (проблема была в сборнике "Реинтеграции" для меня)

query.Select(zv => new
            {
                zv,
                rId = zv.this.Reintegraties.FirstOrDefault().Id
            })
            .Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
                                             && t.HoortBijEntiteitType == EntiteitType.Reintegratie
                                             && t.Type == TaakType))
            .Select(x => x.zv);

надеюсь, это кому-нибудь поможет.

Roelant
источник
6
zv.this.Reintegraties.FirstOrDefault().Idпотенциальный NullReferenceException
2

В моем случае мне удалось решить проблему, выполнив следующие действия:

Я изменил свой код из этого:

var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();

К этому:

var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();
Colin
источник
Это не работает для меня. Как p1и p2оба находятся в памяти, объявлены ли они анонимно или по имени переменной.
Рахат Заман
2
Тип переменной не проблема. В моем случае ошибка была вызвана тем, что выполнял .FirstOrDefault () внутри предложения Where.
Колин
1

Стоит добавить, так как пример кода OP не предоставляет достаточного контекста, чтобы доказать обратное, но я получил эту ошибку также в следующем коде:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
        .FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}

По-видимому, я не могу использовать Int32.Equalsв этом контексте для сравнения Int32 с примитивом int; Я должен был (безопасно) изменить это:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
Джеймс Перих
источник
EF принимает на Equalsотлично.
Герт Арнольд
0

Просто добавьте AsEnumerable () и ToList (), чтобы это выглядело так

db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()

ToList().AsEnumerable()
Халед Салех
источник
0

У меня была эта проблема, и то, что я сделал и решил, это то, что я использовал AsEnumerable()непосредственно перед предложением Join. вот мой запрос:

List<AccountViewModel> selectedAccounts;

 using (ctx = SmallContext.GetInstance()) {
                var data = ctx.Transactions.
                    Include(x => x.Source).
                    Include(x => x.Relation).
                    AsEnumerable().
                    Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
                    GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
                    ToList();
            }

Мне было интересно, почему эта проблема возникает, и теперь я думаю, что это потому, что после того, как вы сделаете запрос через LINQ , результат будет в памяти и не загружен в объекты, я не знаю, что это за состояние, но в некоторых они переходное состояние я думаю. Затем, когда вы используете AsEnumerable()или ToList(), и т. Д., Вы помещаете их в объекты физической памяти, и проблема решается.

ebrahim.mr
источник