Найти все объекты в одном списке, у которых есть свойство, которое соответствует свойству в другом списке объектов.

Проблема

Я пытаюсь запросить таблицу (на основе ModelA), используя другую таблицу (на основе ModelB). Эти модели упрощены для этого примера. Мне нужно сохранить результат как IQueryable, поэтому изменение на Enumerable или List не является вариантом. Тем не менее, я попытался добавить .ToList(), но получил ту же ошибку.

Вытягивание MyId из одного списка в список строк (для использования Contains()) не является вариантом, поскольку может быть слишком много MyIds (> 40k), что вызывает ошибку, указывающую на то, что операция исчерпана из ресурсов, что я Догадываюсь, относится к оперативной памяти.

Ошибка

InvalidOperationException: выражение LINQ ... не может быть переведено. Либо перепишите запрос в форме, которая может быть переведена, либо явно переключитесь на оценку клиента, вставив вызов AsEnumerable (), AsAsyncEnumerable (), ToList () или ToListAsync ().

МодельA

public class ModelA
{
    public string MyId { get; set; }
    public string MyName { get; set; }
}

МодельB

public class ModelB
{
    public string MyId { get; set; }
    public string MyName { get; set; }
}

Попытка

var results = context.ModelA
            .Where(a => ModelB.All(b => b.MyId == a.MyId));

Каким способом (-ами) это можно сделать успешно?


person user3071284    schedule 25.02.2020    source источник
comment
Да, Any - правильный метод для этого. Спасибо.   -  person user3071284    schedule 26.02.2020


Ответы (4)


вы можете попробовать проверить, содержит ли второй список «Any ()» соответствующего идентификатора

var results = context.ModelA
        .Where(a => ModelB.Where(b => b.MyId == a.MyId).Any());

или вы можете попробовать присоединиться

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/join-clause

var results = context.ModelA
    .Where(a => ModelB.
            Any(b => b!= null  && b.id != null 
                  && a!=null && a.id!==null && 
                  b.MyId == a.MyId));

У меня был Select вместо Where, и я проверил нули

person Cato    schedule 25.02.2020
comment
Оба варианта работают, но вариант Join медленнее, чем Where, поэтому я выбрал более быстрый. Мне пришлось создать представление для ModelB, чтобы оно было доступно из того же контекста, что и ModelA (они находятся в разных базах данных). Выбор ответа с тех пор, как был первым. - person user3071284; 26.02.2020

Вы можете попробовать это:

var results = ctx
    .ModelAs
    .Where(ma => ctx.ModelBs.Any(mb => mb.MyId == ma.MyId));

Я пользовался вашими моделями, это мой DbContext:

public class MockContext : DbContext
{
    public MockContext(DbContextOptions<MockContext> options)
        : base(options)
    { }

    public DbSet<ModelA> ModelAs { get; set; }
    public DbSet<ModelB> ModelBs { get; set; }
}

Данные, которые я использовал для проверки:

МодельA:

MyId | MyName

1 Nettie Koch 
2 Karl Kuvalis 
3 Marcus Weissnat 
4 Shannon Hettinger 
5 Wilma Kuvalis 
6 Benny Brown 
7 Amanda Maggio 
8 Claude Kohler 
9 Dawn Ritchie 
10 Alan Ruecker

МодельB:

MyId | MyName

5 Francis Konopelski 
6 Mandy Yost 
7 Marsha Parisian 
8 Crystal Mayer 
9 Sergio Crona 
10 Kenny Rice 
11 Levi Gutkowski 
12 Brandon Haley 
13 Jan Kunze 
14 Rafael Blanda 

Результат:

MyId | MyName

5 Wilma Kuvalis 
6 Benny Brown 
7 Amanda Maggio 
8 Claude Kohler 
9 Dawn Ritchie 
10 Alan Ruecker 
person CarlosMorgado    schedule 26.02.2020
comment
Отличный, исчерпывающий ответ, который работает, спасибо. Мне пришлось создать представление для ModelB, чтобы оно было доступно из того же контекста, что и ModelA (они находятся в разных базах данных). - person user3071284; 26.02.2020

Есть несколько способов добиться этого, вот два для справки:

var result = (from a in context.ModelA
                      join b in context.ModelB
                      on a.MyId equals b.MyId
                      select a);

Или вы можете попробовать этот метод:

 var result = context.ModelA.Join(_context.ModelB,
                        x => x.MyId,
                        y => y.MyId,
                       (x, y) => x);

Дополнительные сведения можно найти по этой ссылке.

person LouraQ    schedule 26.02.2020
comment
Спасибо, я попробовал Join, и он сработал. По некоторым причинам он немного медленнее, чем Where. Мне также пришлось создать представление для ModelB, чтобы оно было доступно из того же контекста, что и ModelA (они находятся в разных базах данных). - person user3071284; 26.02.2020

Вы могли выглядеть Any(), как показано ниже

var results = context.ModelA.Where(a => ModelB.Any(b => b.MyId == a.MyId));
person Nguyễn Văn Phong    schedule 26.02.2020
comment
Как я уже упоминал в разделе комментариев. Вы можете использовать Any() для этого. Не забудьте принять мой ответ, если он был вам полезен. - person Nguyễn Văn Phong; 27.02.2020