删除关系时删除依赖实体
假设我有两个实体,如下所示:
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.PatientId 而不是 Response.Patient 的响应,实体不会加载 Response.Patient 属性,因此我的代码认为它已被孤立并应删除。
总结
我想知道的是,我如何知道实体已被修改,因为它的 FK 关系已被删除。
Say I have two entities like so:
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; }
}
I want to be able to call
Patient.Responses.Remove(someResponse);
And have entity delete not only the relationship but the Response entity as well. At present if I just delete the relationship I get the following error:
System.InvalidOperationException: The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Reading this blog post http://blogs.msdn.com/b/dsimmons/archive/2010/01/31/deleting-foreign-key-relationships-in-ef4.aspx I realised I can achieve this by having the following mapping:
modelBuilder.Entity<Response>().HasKey(m => new { m.Id, m.PatientId });
But I don't want to change my primary key. What I want to do is override DbContext.SaveChanges() and mark for deletion any Responses where the Patient relationship has been deleted. I tried this:
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();
}
But I found it's possible to attach a Response with only Response.PatientId set and not Response.Patient, entity wont have loaded the Response.Patient property so my code thinks it's been orphaned and should be deleted.
In summary
What I want to know is how can I can tell that an entity has been modified because it's FK relationship has been removed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用这个代替:
Use this instead:
您需要配置映射以便发生级联删除。为此,您需要将带有
WillCascadeOnDelete
的模型映射到true
。You need to configure the mappings such that a cascade delete will occur. To do that you need to map the model with
WillCascadeOnDelete
totrue
.我认为我的问题不在于代码,而在于我假设实体的 Attach() 方法如何工作。我假设如果我附加设置了 PatientId 但没有设置 Patient 属性的响应,那么实体将为我填充 Patient 属性。
事实上,我认为发生的情况是实体按原样附加它,然后如果我将该实体标记为已修改并保存它,实体会看到 null Patient 属性并假设我要删除关系,因此会抛出错误,因为它将被孤立(不能将 Response.PatientId 设为 null)。因此,也许一切都按设计工作,并且我的 SaveChanges() 解决方案有效。
I think my problem is not with the code but rather with how I assume entity's Attach() method works. I assumed that if I attach a response with PatientId set but not Patient property then entity would populate the Patient property for me.
In fact what I think happens is entity attaches it as it is, then if I mark that entity as modified and save it, entity sees the null Patient property and assumes I want to remove the relationship, so throws an error because it would be orphaned (can't null Response.PatientId). So perhaps everything is working as designed and my SaveChanges() solution works.