C# Linq для объектов - Как выбрать только записи, которые имеют все ссылки из массива - PullRequest
0 голосов
/ 08 января 2020

У меня есть 2 объекта:

Students
   Id     Name
   1      John Doe
   2      Jack Daniels
   3      Peter Green

Languages
   Language    Student    Result
   English     1          A
   Spanish     2          A
   Italian     2          B
   English     3          B
   Spanish     1          A

У меня есть запрос, чтобы выбрать студентов по языковым результатам

string[] langIds = new string[] { "English", "Italian" };
var result = (from students in context.Students
             where students.Languages.Where(s => langIds.Contains(s.Language)).Count > 0
             orderby students.Languages.Where(s => langIds.Contains(s.Language)).Sum(m => m.Result) descending
             select students);

Запрос дает мне список студентов, упорядоченный по сумме языка Результаты.

Но этот список включает студентов, которые сдали как минимум один языковой результат из указанного массива, где мне нужно выбрать только тех студентов, у которых all языковые результаты из этого массив.

Есть предложения, как решить вопрос?

Ответы [ 2 ]

0 голосов
/ 08 января 2020

Кажется, что между учениками и языками существует связь «многие ко многим»: каждый ученик говорит на ноль или более языков, а на каждом языке говорит ноль или более учеников.

Если вы выполнили Условные обозначения Entity Framework , у вас будет что-то похожее на это:

class Student
{
    public int Id {get; set;}
    ... // other properties

    // Every student speaks zero or more Languages (many-to-many)
    public virtual ICollection<Language> Languages {get; set;}
}
class Language
{
    public int Id {get; set;}
    ... // other properties

    // Every Language is spoken by zero or more Students(many-to-many)
    public virtual ICollection<Student> Students {get; set;}
}

Для полноты Dbcontext:

class MyDbContext : DbContext
{
    public DbSet<Student> Students {get; set;}
    public DbSet<Language> Languages {get; set;}
}

Поскольку вы придерживались соглашений, структура сущности обнаруживает отношение «многие ко многим». Вам не нужно указывать соединительную таблицу для этого, вместо этого вы можете использовать virtual ICollection.

Дайте мне всех учеников, которые говорят по крайней мере на всех языках в объекте LangIds

Всякий раз, когда вы хотите проверить, содержит ли коллекция A хотя бы все элементы из коллекции B, рассмотрите возможность проверки B.Except(A).Any(). Если это правда, то, очевидно, некоторые элементы из B не находятся в A.

Так что, если LangIds.Except(Student.Languages).Any() верно, то вы знаете, что есть языки, на которых ученик не говорит. Вы не хотите этого ученика. Вам нужны только те ученики, у которых Any приводит к ложному результату.

Как только вы это узнаете, код очень прост:

var result = dbContext.Students
    .Where(student => !langIds.Except(student.Languages).Any() // note the "!"
    .ToList();

Это, вероятно, принесет больше свойств, чем вы на самом деле планируете используйте, поэтому рассмотрите возможность добавить Select:

var result = dbContext.Students
    .Where(student => !langIds.Except(student.Languages).Any()
    .Select(student => new
    {
        // Select only the Student properties that you plan to use
        Id = student.Id,
        Name = student.Name,
        ...

        // Only if you plan to use all languages that the Student speaks:
        Languages = student.Languages.Select(language => new
        {
            // again: only the language properties that you plan to use:
            Id = language.Id,
            Code = language.Code,
            Abbreviation = language.Abbreviation,
            ...

            // no need to fill language.Students
        })
        .ToList(),
    });
0 голосов
/ 08 января 2020

Абсолютно простое и очевидное решение, сформулированное Йонасом Хогом в комментариях: вместо

where students.Languages.Where(s => langIds.Contains(s.Language)).Count > 0

используйте

where students.Languages.Where(s => langIds.Contains(s.Language)).Count == langIds.Length

Большое спасибо, Джонас

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