Reputation: 625
I have problems defining an entity that has two one-to-many relations (two lists)
public class Calendar
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Guid ID { get; set; }
public virtual IList<Appointment> FreeSlots { get; set; }
public virtual IList<Appointment> AppointmentsList { get; set; }
...
}
public class Appointment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AppointmentID { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public String Type { get; set; }
public String Info { get; set; }
public Guid CalendarID { get; set; }
public virtual Calendar Calendar { get; set; }
}
And code-first code:
modelBuilder.Entity<Appointment>().HasKey(u => new {u.AppointmentID, u.CalendarID });
modelBuilder.Entity<Appointment>().HasRequired(u => u.Calendar).WithMany(c => c.FreeSlots).HasForeignKey(f => f.CalendarID).WillCascadeOnDelete(true);
modelBuilder.Entity<Appointment>().HasRequired(u => u.Calendar).WithMany(c => c.AppointmentsList).HasForeignKey(f => f.CalendarID).WillCascadeOnDelete(true);
Appointment has two PK because I want the appointment to be deleted if the calendar is deleted.
When I try to add a new appointment to the FreeSlot, I get the following error: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception.
I have tried with this mapping too with no luck:error 0040: Type Calendar_FreeSlots is not defined in the namespace Project.DAL (Alias=Self).
modelBuilder.Entity<Appointment>().HasKey(u => new {u.AppointmentID, u.CalendarID });
modelBuilder.Entity<Calendar>().HasMany(c => c.FreeSlots).WithRequired(c => c.Calendar).HasForeignKey(c => c.CalendarID).WillCascadeOnDelete();
modelBuilder.Entity<Calendar>().HasMany(c => c.AppointmentsList).WithRequired(c => c.Calendar).HasForeignKey(c => c.CalendarID).WillCascadeOnDelete();
I guess the problem is that I have two one-to-many relations to the same type of entity but I do not know the way to make it correctly.
Upvotes: 1
Views: 2458
Reputation: 177143
The mistake in your mapping is that you use Appointment.Calendar
twice for two different relationships. That's not possible. You would need a second pair of FK and navigation properties in Appointment
(or map one relationship without inverse properties):
modelBuilder.Entity<Calendar>()
.HasMany(c => c.FreeSlots)
.WithRequired(c => c.Calendar1)
.HasForeignKey(c => c.Calendar1ID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Calendar>()
.HasMany(c => c.AppointmentsList)
.WithRequired(c => c.Calendar2)
.HasForeignKey(c => c.Calendar2ID)
.WillCascadeOnDelete(true);
(For at least one relationship you must disable cascading delete. Otherwise you'll end up with a multiple cascading delete exception.)
However, I have the feeling that you actually should have only one relationship and collection Calendar.Appointments
and a kind of status in Appointment
, like a bool IsFree
property. You could then always extract the free slots of a calendar entry with calendar.Appointments.Where(a => a.IsFree)
.
Upvotes: 3