10

I have a User model and a Event model in my project. The Event has a creator(User) and has participant(Users) so Event has a one-to-many relationship with User and also a many-to-many relationship to the same table.

I had first the one-to-many relationship like this:

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

Then when I added the many-to-many relationship the migration doesn't generate the many to many relationship:

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; }
      ...
}

If I remove the one-to-many relationship then the migration generates the many-to-many relationship successfully.

Is there a way to do this with only data annotations?

Escobar5
  • 3,941
  • 8
  • 39
  • 62
  • You're right @slauma, excuse my english, is not my native language, I just try to do my best. – Escobar5 Feb 27 '13 at 20:29
  • I edited it, hope is more clear – Escobar5 Feb 27 '13 at 20:31
  • I didn't mean a language thing, but the content (if there are any error messages or exceptions, etc. or if the result is not what you expected, etc.). Anyway, nevermind, the problem seems to be solved already :) – Slauma Feb 27 '13 at 21:01

2 Answers2

16

EF doesn't know where User.Events has to be mapped to. It could be Event.CreatedBy or it could be Event.Users. Both would result in a valid model. You must give EF a little hint what you want by applying the [InverseProperty] attribute:

public class User
{
    ...
    [InverseProperty("Users")]
    public virtual ICollection<Event> Events { get; set; }
    ...
}
Slauma
  • 175,098
  • 59
  • 401
  • 420
8

With Code First Approach, I would always recommend to use fluent API rather than using DataAnnotations, Which uses some conversions automatically.

This way, you'll know what exact configuration you've made.

If I were you, here is what i would use :

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.
    }
}
Amit Andharia
  • 909
  • 1
  • 8
  • 16