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

#c# #.net #entity-framework #.net-core

#c# #.net #entity-framework #.net-ядро

Вопрос:

Я совсем новичок в .NET Entity Framework и в настоящее время я застрял, когда пытаюсь реализовать некоторые отношения между двумя объектами. Я получаю следующее сообщение об исключении:

Не удалось определить связь, представленную свойством навигации ‘Actor.ActiveMovies’ типа ‘ICollection’

Я не знаю, как я правильно определяю эту связь. Объекты movie и actor показаны ниже.

Сущность Movie.cs

     public class Movie
    {
        [Key]
        public Guid MovieId { get; set; }

        public string Title { get; set; }

        public string Description { get; set; }

        public string ThumbnailUrl { get; set; }

        public string Language { get; set; }

        [Required]
        public virtual ICollection<Actor> Actors { get; set; }
    }
  

Объект Actor.cs

     public class Actor
    {
        [Key]
        public Guid ActorId { get; set; }

        public string ProfileImageUrl { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTime BornDate { get; set; }

        public virtual ICollection<Movie> ActiveMovies { get; set; }
    }
  

Чего я хочу достичь

Кажется, что фильмы и актеры имеют отношение «многие ко многим», поскольку в фильме может быть несколько актеров, а актер может быть активным в нескольких фильмах. Хотя я ничего не придумал для этого.

Что я пробовал

Я проверил DatabaseContext и подумал, что смогу реализовать многие для многих следующим образом.

             modelBuilder.Entity<Movie>(entity =>
            {
                entity.HasKey(movie => movie.MovieId);
                entity.Property(movie => movie.Actors).IsRequired();
                entity.HasMany<Actor>(movie => movie.Actors);
            });

            modelBuilder.Entity<Actor>(entity =>
            {
                entity.HasKey(actor => actor.ActorId);
                entity.HasMany<Movie>(actor => actor.ActiveMovies);
            });
  

Но это дало мне сообщение об исключении

Свойство или навигация ‘Actors’ не могут быть добавлены к типу объекта ‘Movie’, поскольку свойство или навигация с тем же именем уже существуют для типа объекта ‘Movie’.

Я был бы признателен за любую информацию в этом случае!

Комментарии:

1. Для отношения «многие ко многим» требуется таблица распределения вместо списков, и вы ссылаетесь на нее как actorID, так и MovieID (с другими столбцами, если хотите, например, имя сыгранного персонажа, роль, что угодно). С помощью этого вы можете создать несколько записей для одного и того же фильма (разных актеров), и один и тот же актер может быть в нескольких фильмах. Это может быть личным, но я предпочитаю создавать новую сущность, чем использовать списки и работать с ModelBuilder.

Ответ №1:

Вам необходимо полностью определить взаимосвязь. В этом случае мы используем отдельную таблицу. Попробуйте это.

  public class Movie
    {
        public Guid MovieId { get; set; }

        public string Title { get; set; }

        public string Description { get; set; }

        public string ThumbnailUrl { get; set; }

        public string Language { get; set; }

        public virtual ICollection<MovieActor> MovieActors { get; set; }
    }



 public class Actor
    {
        public Guid ActorId { get; set; }

        public string ProfileImageUrl { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTime BornDate { get; set; }

        public virtual ICollection<MovieActor> MovieActors { get; set; }
    }

  public class MovieActor
    {
   public int MovieId { get; set; }

   public Movie Movie { get; set; }

   public int ActorId { get; set; }

   public Actor Actor{ get; set; }
    }
  

и в вашем OnModelCreating()

   modelBuilder.Entity<MovieActor>()
            .HasKey(x=> new { x.ActorId, x.MovieId });  

       modelBuilder.Entity<MovieActor>()
            .HasOne(bc => bc.Movie)
            .WithMany(b => b.MovieActors)
            .HasForeignKey(bc => bc.MovieId);

        modelBuilder.Entity<MovieActor>()
            .HasOne(bc => bc.Actor)
            .WithMany(c => c.MovieActors)
            .HasForeignKey(bc => bc.ActorId);
  

Комментарии:

1. Я бы добавил определенный идентификатор (или Guid) в MovieActor таблицу и удалил обе ICollections.

2. Это тоже правильно ! , Но исправил код по своему стилю. Это также будет работать.

3. Ах, хорошо, что это работает таким образом. Я собираюсь протестировать это завтра. Нужен ли новому объекту как объект Movie, так и MovieID? Или это ошибка во фрагменте кода?

4. Конечно, для этого нужны как объект Movie, так и MovieID. Это основной момент создания отношений «многие ко многим».

Ответ №2:

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

Появление в .net 5 и EF core 5.x — это та функция, которая будет примерно работать как

  builder.Entity<Movie>()
        .HasMany(m=>m.Actions)
        .WithMany(a=>a.Movies); // Invented syntax, the feature has not been released yet.
  

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

 builder.Entity<MovieActor>()
       .HasKey(ma => new { ma.MovieId, ma.ActorId });

builder.Entity<Movie>()
       .HasMany(m=>m.MoiveActors)
       .WithOne(ma=>ma.Movie);

builder.Entity<Actor>()
       .HasMany(m=>m.MoiveActors)
       .WithOne(ma=>ma.Actor);