在一对多关系中初始化子实体会导致重复

时间:2018-09-30 14:02:31

标签: sql wpf entity-framework

我碰到了那个question。我的问题很相似。

我有两个EF班的约会和工作。它们之间具有一对多的关系。

 public class Appointment
{

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int AppointmentID { get; set; }
    public int AppointmentStatus { get; set; }
    public string Remarks { get; set; }
    public ICollection<Job> Job {get; set; }

}
 public class Job
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int JobId { get; set; }
    public string JobName { get; set; }
    public string JobDescription { get; set; }
    public short JobMode { get; set; }
    public virtual Appointment Appointments { get; set; }

}

当我尝试将作业添加到约会实例时,我收到nullreferenceexception。由于约会的Job属性返回null。到目前为止很正常。

为处理该异常,我尝试在父项的约束中添加一个块,以在创建约会时初始化新的Job项目。

       public Appointment()
    {
        if (this.Job == null)
        {
            this.Job = new Collection<Job>();
        }
    }

那时候,我不再得到nullreferenceexception,但是该解决方案导致重复的Job项目。成功创建了新约会,但不是我选择的工作(!)。实际上是我选择的工作的一个实例。每次创建新的工作实例并将其与新创建的约会相关联。

example job

1 个答案:

答案 0 :(得分:1)

我建议您坚持使用Entity Framework Code-First conventions。它使您和以后阅读您代码的人的生活更加轻松。

在您的情况下,这意味着每个Appointment都具有零个或多个Jobs,并且每个Job都使用外键恰好属于一个Appointment

class Appointment
{
    public int Id {get; set;}

    // every Appointment has zero or more Jobs:
    public virtual ICollection<Job> Jobs {get; set;}

    ...
}

class Job
{
    public int Id {get; set;}

    // every Job belongs to exactly one Appointment using foreign key:
    public int AppointmentId {get; set;}
    public virtual Appointment Appointment {get; set;}

    ...
}

因为我坚持约定,所以实体框架能够检测一对多关系。它检测主键和外键:不需要属性,也不需要流畅的API。

  

在Entity Framework中,表中的列是非虚拟属性   在你的课上。表之间的关系(一对多,多对多,   ...)被标记为虚拟:它们不是您表中的真实项目

这只是一个建议,如果您有充分的理由偏离约定,那么您当然可以这样做。

但是,必须将表之间的关系定义为虚拟。您还需要定义外键。

完成此操作后,您提取的约会将没有空的职位:

var fetchedAppointment = dbContext.Appointments
    .Where(appointment => appointment.Id = ...)
    .FirstOrDefault();
// fetchedAppointment.Jobs is not null!

// add a new Job:
fetchedAppointment.Jobs.Add(new Job()
{
     // no need to fill the Id, nor the foreign key. Entity Framework will do that for you
     JobName = ...,
     JobDescription = ...,
     ...
});
dbContext.SaveChanges();

但是,如果要添加一个或多个职位的新约会,则必须自己添加。您可以使用数组或列表,没关系,只要它实现ICollection<Job>

var addedAppointment = dbContext.Appointments.Add(new Appointment()
{
    // no need to fill the Id: entity framework will do that for you
    AppointmentStatus = ...
    Remarks = ...

    Jobs = new List<Job>()
    {
         // again: no need to fill the Id, nor the foreign key.
         // Entity Framework will do that for you
         new Job()
         {
             JobName = ...,
             JobDescription = ...,
         },
         new Job()
         {
             JobName = ...,
             JobDescription = ...,
         },
         ...
    },
});

// if you want, you can also add a Job here:
addedAppointment.Jobs.Add(new Job()
{
    JobName = ...,
    JobDescription = ...,
});

// All primary and foreign keys will be filled as soon as you call SaveChanges
dbContext.SaveChanges();

当然,您也可以将作业所属的约会添加到上下文中

var addedJob = dbContext.Jobs.Add(new Job()
{
    JobName = ...,
    JobDescription = ...,

    // this Job is a job of addedAppointment
    Appointment = addedAppointment,
}

或者如果您已经保存了约会,则主键具有一个值:

var addedJob = dbContext.Jobs.Add(new Job()
{
    JobName = ...,
    JobDescription = ...,

    // fill the foreign key instead
    AppointmentId = addedAppointment.Id
},