EF Core: множественные отношения «многие ко многим» между одними и теми же объектами - PullRequest
1 голос
/ 24 марта 2020

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

В моем проекте есть пользователи, сериалы и эпизоды. Мы будем игнорировать эпизоды для простоты здесь. У пользователей есть любимые серии и список наблюдения.

public class User 
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string FullName { get; set; }

    public List<UserSeries> WatchList { get; }
    public List<UserSeries> FavoriteSeries { get; }
}

Объект объединения:

public class UserSeries
{
    public int UserId { get; set; }
    public User User { get; set; }

    public int SeriesId { get; set; }
    public Series Series { get; set; }
}

Объект серии не так важен, это стандартный тип объекта.

Теперь я пытаюсь создать конфигурации для EF Core, я делаю это с помощью Fluent API Configurations (IEntityTypeConfiguration). Сначала я попытался сделать UserSeriesConfiguration следующим образом:

class UserSeriesConfiguration : IEntityTypeConfiguration<UserSeries>
{
    public void Configure(EntityTypeBuilder<UserSeries> builder)
    {
        builder.ToTable("UserSeries");
        builder.HasKey(us => new { us.UserId, us.SeriesId });

        builder.HasOne(us => us.User).WithMany(u => u.FavoriteSeries).HasForeignKey(ue => ue.UserId);
        builder.HasOne(us => us.User).WithMany(u => u.WatchList).HasForeignKey(us => us.UserId);
        builder.HasOne(us => us.Series).WithMany().HasForeignKey(us => us.SeriesId);
    }
}

EF Core пожаловался:

Невозможно создать связь между 'User.WatchList' и 'UserSeries.User' потому что уже существует связь между User.FavoriteSeries и UserSeries.User. Свойства навигации могут участвовать только в одной взаимосвязи.

Я пытался создать UserFavoriteSeriesConfiguration и UserWatchListConfiguration и дать им отдельные имена таблиц, но это довольно уродливо, из-за дублирования кода и множество дополнительных классов конфигурации (особенно потому, что с эпизодами и т. д. c. У меня есть эта настройка тоже), и хуже всего: он все еще не работает ...

Есть ли простое решение этой проблемы ? В худшем случае мне придется создавать объекты объединения (вместо UserSeries можно сделать UserFavoriteSeries), но это удваивает негативы, которые я описывал в предыдущих параграфах: множество дополнительных классов и дублирующий код.

1 Ответ

1 голос
/ 24 марта 2020

«faved» ser ie отличается от отношения «watchlisted» ser ie, поэтому вам необходимо каким-то образом различать эти два различных типа отношений при хранении данных в базе данных. .

Сейчас у вас есть только одна таблица для сопоставления обоих отношений, и вот что происходит:

Situation now

Вы видите проблема? В таблице UserSerie есть повторяющаяся строка, вероятно, потому что Diego пометил как Fav ser ie Bojack, и он также добавил ее к своему Watchlist. Однако невозможно определить, какая строка представляет отношение Fav, а какая представляет отношение Watchlisted.

Первый подход: добавить дополнительный атрибут к UserSerie в качестве дискриминатора

Один из подходов - добавить новый атрибут (столбец таблицы базы данных) для хранения типа отношений между User и Serie.

Add attribute approach

Теперь вы можете ясно видеть, какой тип отношений представляет каждая строка: F is любимая серия ie и W список наблюдения * ie.

Было бы очень легко добавить другие типы отношений (серии, которые рекомендуют, серии, которые не нравятся, или что-то еще).

Это означает, что теперь у сущности User будет только один список UserSerie, где у каждого UserSerie есть свойство Type, которое можно проверить, чтобы определить тип отношений между этим пользователем и этой службой ie.

public class User 
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string FullName { get; set; }

    public List<UserSeries> Series { get; }
}

Второй подход: добавить дополнительную таблицу отношений`

Другой подход заключается в том, чтобы иметь разные таблицы для каждого отношения:

enter image description here

public class User 
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string FullName { get; set; }

    public List<UserFavedSeries> FavedSeries { get; }
    public List<UserWatchlistedSeries> WatchlistedSeries { get; }

}

Это я и что если в будущем вы не захотите добавлять дополнительные отношения, вам нужно создать еще одну таблицу.

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

...