Entity Framework Code First: отношения "один ко многим" и "многие ко многим" в одну таблицу

У меня есть модель User и модель Event в моем проекте. У события есть создатель (Пользователь) и участник (Пользователи), поэтому у события есть отношения "один ко многим" с пользователем, а также отношение "многие ко многим" к одной и той же таблице.

У меня сначала были отношения "один ко многим" :

Public class Event
{
      ...
      public int CreatedById { get; set; }
      public virtual User CreatedBy { get; set; }
      ...
}

Затем, когда я добавил отношения "многие ко многим" , миграция не создает отношения "многие-многие":

Public class User
{
      ...
      public virtual ICollection<Event> Events { get; set; }
      ...
}

Public class Event
{
      ...
      public int CreatedById { get; set; }
      public virtual User CreatedBy { get; set; }
      public virtual ICollection<User> Users { get; set; }
      ...
}

Если я удалю отношения "один ко многим" , то миграция успешно создает отношения "многие ко многим" .

Есть ли способ сделать это только с аннотациями данных?

Ответ 1

EF не знает, где должно быть сопоставлено User.Events. Это может быть Event.CreatedBy, или оно может быть Event.Users. Оба они приведут к действительной модели. Вы должны дать EF небольшой намек на то, что вы хотите, применив атрибут [InverseProperty]:

public class User
{
    ...
    [InverseProperty("Users")]
    public virtual ICollection<Event> Events { get; set; }
    ...
}

Ответ 2

С первым подходом кода я всегда рекомендую использовать свободный API, а не использовать DataAnnotations, который автоматически использует некоторые преобразования.

Таким образом, вы узнаете, какую именно конфигурацию вы сделали.

Если бы я был вами, вот что я буду использовать:

public class EventMap : EntityTypeConfiguration<Event>
{
    public EventMap()
    {
        this.HasRequired(m => m.CreatedBy) // envent must have a creator
            .WithMany() // a user can have 0,1 or more events created by him
            .HasForeignKey(m => m.CreatedById) // specify property to be used as FK
            .WillCascadeOnDelete(true); // delete all events created by user if that specific user is deleted

        this.HasMany(m=>m.Users) // an event can have 0,1 or more participants
            .WithMany(m=>m.Events) // a user can be a participant in 0,1 or more events                
            .Map(m => m.MapLeftKey("EventId").MapRightKey("UserId")); // this will generate intermediate table to hold participant information - dbo.EventUser with EventId & UserId
            // Cascade Delete is always true for Many to Many mapping. however, it doesn't delete entry in other table, it deletes entry in Joined Table only.
    }
}