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.

有帮助吗?

解决方案

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).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top