Инициализация дочерней сущности в отношениях «один ко многим» приводит к дублированию - PullRequest
0 голосов
/ 30 сентября 2018

Я сталкивался с этим вопросом .Моя проблема очень похожа.

У меня есть два класса EF Appointment и Job.Имеет отношения один ко многим среди них.

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

}

Когда я пытаюсь добавить работу к экземпляру Назначения, я получаю исключение nullreference.Из-за свойства Job назначения, возвращающего нуль.Пока это нормально.

Для обработки этого исключения я попытался добавить блок в ограничение Родителя для инициализации нового элемента Job при создании Назначения.

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

В это время я больше не получаю исключение nullreferenceexception, но это решение вызывает дублирование задания.Новое назначение успешно создано, но (!), Не моя выбранная работа.На самом деле экземпляр моей выбранной работы.Каждый раз создается новый экземпляр задания и связывается с вновь созданным Назначением.

example job

1 Ответ

0 голосов
/ 01 октября 2018

Советую придерживаться Условий Entity Framework Code-First .Это облегчает жизнь вам и тем, кто будет читать ваш код в будущем.

В вашем случае это означает, что каждый 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
},
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...