LINQ to Entities: выполнять соединения по отношениям «многие ко многим» (сначала код) - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть следующая модель:

[Table("Experiments")]
public class Experiment
{
    ...

    public virtual ICollection<ExperimentType> ExperimentTypes { get; set; }

    public Experiment()
    {
        ExperimentTypes = new List<ExperimentType>();
    }
}

[Table("ExperimentTypes")]
public class ExperimentType
{
    ...

    public virtual ICollection<Experiment> Experiments { get; set; }

    public ExperimentType()
    {
        Experiments = new List<Experiments>();
    }
}

DbSet содержит:

    public DbSet<Experiment> Experiments { get; set; }
    public DbSet<ExperimentType> ExperimentTypes{ get; set; }

И это создает таблицу на SQL, которая называется ExperimentExperimentTypes.

Теперь я хотел бы выполнить соединение LINQ, например:

var query =
   from e in database.Experiments
   join eet in database.ExperimentExperimentTypes on eet.Experiment_Id equals eet.ExperimentType_Id ...

Но очевидно, что database.ExperimentExperimentTypes не распознан в коде.

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

Как этого добиться?

1 Ответ

0 голосов
/ 14 ноября 2018

Итак, у вас есть две таблицы: Experiment и ExperimentType. Между этими двумя существует отношение «многие ко многим»: каждый Experiment является экспериментом с нулем или более ExperimentTypes; каждый ExperimentType является типом ноль или более Experiments.

Это многие ко многим можно увидеть в определениях вашего класса. virtual ICollection<...> с обеих сторон указывает на отношение «многие ко многим».

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

Но как мне выполнить соединение экспериментов ExperimentTypes, если я не могу получить доступ к распределительной таблице?

Что ж, медведь Пух должен вернуться к своей мыслительной точке. Он не хочет присоединяться к столам, он хочет, чтобы все (или некоторые) Experiments, каждый со всеми (или некоторыми) его ExperimentTypes.

Так почему бы просто не выполнить запрос, используя ICollection<...>?

var experiments = myDbContext.Experiments
    .Where(experiment => ...)              // only if you don't want all experiments
    .Select(experiment => new
    {   // Select only the properties you actually plan to use
        Id = experiment.Id,
        Name = experiment.Name,
        ...

        // get all or some of its ExperimentTypes
        ExperimentTypes = experiment.ExperimentTypes
             .Where(experimentType => ...)  // only if you don't want all experiment types
             .Select(experimentType => new
             {
                  // again: select only the properties you plan to use
                  Id = experimentType.Id,
                  ...
             })
             .ToList(),
    });

Платформа сущностей знает «многие ко многим», она знает, что для этого необходимо тройное соединение с таблицей соединений, и будет выполнять это тройное соединение.

Внутренне это будет GroupJoin , вы получите Experiments, каждый со своими ExperimentTypes. Вы даже получаете Эксперименты, которые еще не имеют ExperimentType.

Если вы действительно хотите inner join, вам придется сгладить эксперименты с их типами экспериментов. Это делается с использованием перегрузки для SelectMany, в которой в качестве параметра

используется resultSelector.
// flatten the Experiments with their experimentTypes
var flatInnerJoin = myDbContext.Experiments.SelectMany(experiment => experiment.ExperimentTypes,

    // from each experiment and one of its experimentTypes make one new object
    (experiment, experimentType) => new
    {
        ExperimentId = experiment.Id,
        ExperimentTypeId = experimentType.Id,
        ...
     });
 })

Нет, лучше! Таким образом, вы не получите эксперименты, которые не имеют ExperimentTypes, как в стандартном внутреннем объединении.

...