Удалить зависимую сущность при удалении отношений - PullRequest
0 голосов
/ 07 сентября 2011

Скажем, у меня есть две сущности, такие как:

public class Response 
{
  public int Id { get; set; }
  public int PatientId { get; set; }
  public virtual Patient Patient { get; set; }
  public string Text { get; set; }
}

public class Patient
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Response> Responses { get; set; }
}

Я хочу иметь возможность звонить

Patient.Responses.Remove(someResponse);

И иметь сущность, удаляющую не только связь, но и сущность ответа.,В настоящее время, если я просто удаляю отношение, я получаю следующую ошибку:

System.InvalidOperationException: операция не выполнена: отношение не может быть изменено, поскольку одно или несколько свойств внешнего ключа не являютсяобнуляемый.Когда в отношение вносится изменение, для соответствующего свойства внешнего ключа устанавливается нулевое значение.Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, свойству внешнего ключа должно быть назначено другое ненулевое значение или несвязанный объект должен быть удален.

Чтениеэтот пост в блоге http://blogs.msdn.com/b/dsimmons/archive/2010/01/31/deleting-foreign-key-relationships-in-ef4.aspx Я понял, что могу добиться этого, имея следующее отображение:

modelBuilder.Entity<Response>().HasKey(m => new { m.Id, m.PatientId }); 

Но я не хочу менять свой первичный ключ.Я хочу переопределить DbContext.SaveChanges () и пометить для удаления все ответы, в которых была удалена связь с пациентом.Я попробовал это:

public override int SaveChanges()
{
  // Need to manually delete all responses that have been removed from the patient, otherwise they'll be orphaned.
  var orphanedResponses = ChangeTracker.Entries().Where(
    e => e.State == EntityState.Modified &&
      e.Entity is Response &&
        e.Reference("Patient").CurrentValue == null);
  foreach (var orphanedResponse in orphanedResponses)
  {
    Responses.Remove(orphanedResponse.Entity as Response);
  }

  return base.SaveChanges();
}

Но я обнаружил, что возможно прикрепить Response только с установленным Response.PatientId, но не Response.Patient, сущность не загрузит свойство Response.Patient, поэтому мой код считает, что он потеряни должен быть удален.

В итоге

Я хочу знать, как я могу сказать, что объект был изменен, поскольку его отношение FK было удалено.

Ответы [ 3 ]

2 голосов
/ 07 сентября 2011

Используйте это вместо:

public override int SaveChanges()
{
    var responses = Responses.Local.Where(r => r.Patient == null);
    foreach (var response in responses.ToList())
    {
        Responses.Remove(response);
    }

    return base.SaveChanges();
}
1 голос
/ 09 сентября 2011

Я думаю, что моя проблема не в коде, а в том, как я предполагаю, что метод Attach () объекта работает. Я предположил, что если я прикреплю ответ с установленным PatientId, но не со свойством Patient, то сущность заполнит для меня свойство Patient.

На самом деле, я думаю, что сущность присоединяет ее как есть, тогда, если я отмечаю эту сущность как измененную и сохраняю ее, сущность видит нулевое свойство Patient и предполагает, что я хочу удалить связь, поэтому выдает ошибку, поскольку будет осиротевшим (не может иметь значение Response.PatientId). Так что, возможно, все работает так, как задумано, и мое решение SaveChanges () работает.

1 голос
/ 07 сентября 2011

Вам необходимо настроить сопоставления таким образом, чтобы происходило каскадное удаление.Для этого вам нужно сопоставить модель с WillCascadeOnDelete на true.

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Patient>()
           .HasMany(patient=> patient.Responses)
           .WithRequired(response => response.Patient)
           .HasForeignKey(response => response.PatientId)
           .WillCascadeOnDelete(true);
    }
}
...