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