我认为这有一个非常简单的答案。我是实体框架的新手,我正在创建一个由Contacts
和Groups
组成的测试应用程序作为对象/实体。
以下是删除群组的代码:
private void button_DeleteGroup_Click(object sender, EventArgs e)
{
var _selectedGroup = dataGridView_Groups.SelectedRows[0].DataBoundItem as Group;
try
{
cgContext.Groups.Remove(_selectedGroup);
cgContext.SaveChanges();
PopulateGroupGrid();
MessageBox.Show("Successfully deleted group from database!");
}
catch(Exception ex) { MessageBox.Show("Failed to delete group from database.\r\n\r\n" + ex); }
}
如果删除联系人所属的组,为了测试参照完整性,会抛出异常(应该这样):
" DELETE语句与REFERENCE约束冲突 " FK_dbo.Contacts_dbo.Groups_Group_Id&#34 ;.冲突发生在 数据库" ContactGroups",table" dbo.Contacts",column '分组ID&#39 ;.该声明已被终止。"
然后我捕获此异常并向用户显示一条消息。如果我然后去添加新组或联系人或执行任何操作,则事务将失败并出现与以前相同的异常:
" DELETE语句与REFERENCE约束冲突 " FK_dbo.Contacts_dbo.Groups_Group_Id&#34 ;.冲突发生在 数据库" ContactGroups",table" dbo.Contacts",column '分组ID&#39 ;.该声明已被终止。"
因此,显然我不会在发生初始异常时清除/结束事务。我做错了什么或错过了什么?
答案 0 :(得分:1)
对WithOptional使用WillCascadeOnDelete(true)
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
使用包含
var adv = db.Adv.Include(b => b.Features)
.Include(b => b.AdvDetails)
.Include(b => b.AdvGallery)
.FirstOrDefault(b => b.Id == id);
db.Adv.Remove(adv);
for .HasMany(...)。WithMany(...)Include is ok
答案 1 :(得分:0)
如果实体框架中存在约束违规或其他无效实体状态,则必须将状态恢复为有效/良好状态,以便继续保持更改。
This answer详细介绍了如何做到这一点。
Contacts表和Groups表之间存在外键约束。根据外键(FK)FK_dbo.Contacts_dbo.Groups_Group_Id
,每个联系人都有一个组的引用。
在上面的代码中,删除了一个组。在执行此操作之前,应进行检查以确保没有引用该组的联系人,或者应删除该组中的联系人。该方法取决于您的业务逻辑。
删除依赖项后(即通过Contacts.GroupId引用Group的任何联系人),可以在不违反FK的情况下删除该组。
答案 2 :(得分:0)
实体框架也称为持久性存储。因为它会保留实体的状态以及原始值和修改后的值。它实际上是跟踪实体。
EntityStateEntry具有EF中每个实体的条目。因此,当您调用cgContext.Groups.Remove(_selectedGroup)
时,它会将实体的状态更改为已删除。
现在,您正在删除与其相关联的人员组。因此,参照完整性不会让您删除_selectedGroup
并且您收到错误。但_selectedGroup
的状态保留为Deleted
。现在,当您添加新组时,请在添加组后调用cgContext.SaveChange()
。这会尝试同时保存更改 - 添加新组,并删除_selectedGroup
。但同样,删除违反了FK,你也会得到同样的错误。
要使其有效,您可以使用TransactionScope
。请参阅用法here。