Таблица ключей доступа EF 6 в отношении m: n - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть первая модель кода EF 6 с отношением: m.Таблица между курсами и интересами имеет ключи This2Courses и This2Interests.

Я использую

        modelBuilder.Entity<Course>()
            .HasMany(e => e.Interests)
            .WithMany(e => e.Courses)
            .Map(m => {
                m.ToTable("Interests2Courses");
                m.MapLeftKey("This2Course");
                m.MapRightKey("This2Interest");
            });


        modelBuilder.Entity<Interest>()
            .HasMany(e => e.Courses)
            .WithMany(e => e.Interests)
            .Map(m => {
                m.ToTable("Interests2Courses");
                m.MapLeftKey("This2Interest");
                m.MapRightKey("This2Course");
            });

В классе курса у меня есть

        public virtual ICollection<Interests2Courses> Interests2Courses { get; set; }
    public virtual ICollection<Interest> Interests { get; set; }

, который отлично работает дляИнтересует коллекция.Но когда я пытаюсь получить доступ (загрузить) таблицу ссылок следующим образом:

Course cO = dbC.Courses.Include(a => a.Interests2Courses).FirstOrDefault(a => a.ShortName == "K1");

, я получаю исключение: Неверное имя объекта dbo.Interests2Courses1

Так что я могу получить доступ только к"просто n: m" или таблица ссылок.Есть ли способ получить доступ к обоим?

1 Ответ

0 голосов
/ 11 февраля 2019

Таким образом, каждый Course будет иметь ноль или более Interests, а каждый Interest будет иметь ноль или более Courses.Вы правы, в реляционной базе данных это реализовано с помощью соединительной таблицы.Однако ваша структура сущностей является абстракцией вашей базы данных, вам не нужно определять эту соединительную таблицу:

class Course
{
    public int Id {get; set;}
    ...

    // every Course has zero or more Interests (many-to-many)
    public virtual ICollection<Interest> Interests {get; set;}
}
class Interest
{
    public int Id {get; set;}
    ...

    // every Interest has zero or more Courses(many-to-many)
    public virtual ICollection<Course> Courses{get; set;}
}

Для полноты dbContext

class MyDbContext : DbContext
{
    public DbSet<Course> Courses {get; set;}
    public DbSet<Interest> Interests {get; set;}
}

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

Нет необходимости ни в атрибутах, ни в свободном API.Только если вы не удовлетворены идентификаторами по умолчанию, которые Entity Framework придумал для вас, вам потребуется свободный API.

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

Ответ: не делайте (групповое) объединение, используйте виртуальные ICollections!

Дайте мне все (или некоторые) курсы со всеми(или некоторые) из его интересов

var result = dbContext.Courses
    .Where(course => ...)       // only if you don't want all Courses
    .Select(course => new
    {
        // only select the properties you actually plan to to use
        Id = course.Id,
        Name = course.Name,
        ...

        Interests = course.Interests
            .Where(interest => ...)  // only if you don't want all its Interests
            .Select(interest => new
            {
                 Id = interest.Id,
                 ...
            })
            .ToList(),
    });

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

Добавление после комментария

Если ваша распределительная таблица не является чистой соединительной таблицей, потому что она имеет некоторыесвойства, которые вам нужно добавить в свой DbContext.В этом случае вам нужно будет добавить класс, который представляет этот JunctionItem.

TODO: придумать имя, которое правильно описывает, что представляет этот JunctionItem

Обратите внимание, что ваше отношение «многие ко многим» междуКурсы и Интересы изменяются на один к многим между Курсами и Соединением.Соотношение между Junction и интересами также меняется на один ко многим.

class Course
{
    public int Id {get; set;}
    ...

    // every Course has zero or more JunctionItems (one-to-many)
    public virtual ICollection<JunctionItem> JunctionItems {get; set;}
}
class Interest
{
    public int Id {get; set;}
    ...

    // every Interest has zero or more JunctionItems(one-to-many)
    public virtual ICollection<JunctionItem> JunctionItems{get; set;}
}

Новый класс JunctionItem:

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

    // every JunctionItem belongs to exactly one Course (using foreign key)
    public int CourseId {get; set;}
    public virtual Course Course {get; set;}

    // every JunctionItem belongs to exactly one Interest (using foreign key)
    public int InterestId {get; set;}
    public virtual Interest Interest {get; set;}
}

И DbContext:

class MyDbContext : DbContext
{
    public DbSet<Course> Courses {get; set;}
    public DbSet<Interest> Interests {get; set;}

    public DbSet<JunctionItem> JunctionItems {get; set;}
}

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

var junctionEntity = modelBuilder.Entity<JunctionItem>();

// every junctionEntity has one-to-many with Course:
junctionEntity.HasRequired(junction => junction.Course)
   .WithMany(course => course.JunctionEntities)
   .HasForeignKey(junction => junction.CourseId);

Что-то похожее для интересов:

junctionEntity.HasRequired(junction => junction.Interest)
    .WithMany(interest => interest.JunctionEntities)
    .HasForeignKey(junction => junction.InterestId);

Примечание: оптимизация будет заключаться в объединении JunctionTable.CourseId и JunctionTable.InterestId в один составной первичный ключ:

junctionEntity.HasKey(junction => new {junction.CourseId, junction.InterestId});

Запрещается, чтобы два отдельных элемента JunctionItems указывали на одну и ту же комбинацию (курс, интерес):

Course courseA = ...
Interest interestB = ...

// not possible:
JunctionInterest j1 = new JunctionInterest {Course = courseA, Interest = interestB};
JunctionInterest j2 = new JunctionInterest {Course = courseA, Interest = interestB};

Если вы хотите это, вам потребуется отдельный первичный ключ вваш JunctionItem.

Ваши запросы будут похожи на ваши чистые многие ко многим, но теперь они один ко многим.Не используйте объединение, используйте ICollection:

var result = dbContext.Courses
    .Select(course => new
    {
        Id = course.Id
        Name = course.Name,
        ...

       JunctionItems = course.JunctionItems.Select(junctionItem => new
       {
            ... // junction item properties

            Interests = junctionItem.Interest.Select(interest => new
            {
                 ... // interest properties
            })
            .ToList(),
       })
       .ToList(),
    });
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...