c# - C# Winforms:禁用跟踪绑定的 EF 对象以避免上下文更新,直到按下“更新”
问题描述
因此,我有一个带有绑定到 a 的类别列表的表单DataGridView
,当我双击其中一行时,会打开一个包含该类别详细信息的新表单,并且还允许用户编辑或删除所选类别.
这是两种形式的代码:
FrmCategoryList.cs
public partial class FrmCategoryList : Form
{
private readonly DbContext dbContext;
public FrmCategoryList()
{
InitializeComponent();
dbContext = new DbContext();
}
private void FrmCategoryList_Load(object sender, EventArgs e)
{
FillGrid();
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
FillGrid();
}
private void dgvCategories_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
var grid = (DataGridView)sender;
if (e.RowIndex >= 0)
{
var category = (Category)grid.Rows[e.RowIndex].DataBoundItem;
var frmCategoryView = new FrmCategoryView(category.Id, dbContext);
if (frmCategoryView.ShowDialog() == DialogResult.OK)
FillGrid();
}
}
private void btnNew_Click(object sender, EventArgs e)
{
var frmCategoryView = new FrmCategoryView(0, dbContext);
if (frmCategoryView.ShowDialog() == DialogResult.OK)
FillGrid();
}
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}
private void FillGrid()
{
categoryBinding.DataSource = dbContext.Categories.Where(p => p.Description.StartsWith(txtSearch.Text)).ToList();
}
private void FrmCategoryList_FormClosing(object sender, FormClosingEventArgs e)
{
dbContext?.Dispose();
}
}
FrmCategoryView.cs
public partial class FrmCategoryView : Form
{
private readonly DbContext dbContext;
private Category category;
public FrmCategoryView(int categoryId, DbContext dbContext)
{
InitializeComponent();
this.dbContext = dbContext;
if (categoryId == 0)
{
category = new Category();
btnSave.Visible = true;
}
else
{
category = dbContexto.Categories.Include(c => c.Products).FirstOrDefault(c => c.Id == categoryId);
btnUpdate.Visible = true;
btnDelete.Visible = true;
}
}
private void FrmCategoryView_Load(object sender, EventArgs e)
{
txtDescription.DataBindings.Add("Text", category, "Description");
}
private void btnSave_Click(object sender, EventArgs e)
{
if (category.Validate(dbContext))
{
dbContext.Categories.Add(category);
dbContext.SaveChanges();
MessageBox.Show("Category added!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
}
private void btnUpdate_Click(object sender, EventArgs e)
{
if (category.Validate(dbContext))
{
dbContext.Categories.Attach(category);
dbContext.Entry(category).State = EntityState.Modified;
dbContext.SaveChanges();
MessageBox.Show("Category updated!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
if (MessageBox.Show("¿Are you sure to delete this category?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
if (category.Products.Count > 0)
{
MessageBox.Show("You cannot delete a category with dependencies.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
dbContext.Categories.Remove(category);
dbContext.SaveChanges();
MessageBox.Show("Category deleted!.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
}
private void btnClose_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
因此,当我编辑某个类别的某个字段,然后在不按更新按钮的情况下关闭表单时,问题就来了。在关闭之前不会释放上下文FrmCategoryList
,并且类别对象从FrmCategoryView
绑定到文本,因此更新上下文但不会将更改保存到数据库中。因此,如果我打开其他类别并实际更新它,则在调用时也会保存先前SaveChanges()
的更改,因为上下文会跟踪用户“丢弃”的更改。
我该怎么做才能解决这个问题?我可以在 中重新初始化上下文FrmCategoryView
,但是如果我实际保存某些内容,更改将不在FrmCategoryList
上下文中,而且我不知道如何强制 EF 检查数据库,即使已经跟踪的对象也是如此。
此外,也许有一些方法可以将对象从上下文中分离出来,然后在按下更新按钮时重新附加它。我尝试使用 AsNoTracking() 但尝试重新附加更新时发生错误:它是重复的,因为该对象的实例是在列表表单中创建的。
对不起我的英语不好,希望你能理解!
编辑:
现在,我尝试使用FrmCategoryView
构造函数中的 Id 将类别的实体状态设置为已分离,并使用:
dbContext.Entry(category).State = EntityState.Detached;
我第一次关闭视图表单时它不起作用:网格行得到更新,因为上下文已更新,即使category
条目设置为分离。但接下来的一次,它没有发生。它的工作方式就像它应该工作一样。我所做的更改category
不会被上下文跟踪,直到我重新附加它并在更新按钮上保存更改。
解决方案
这里的问题是你使用过ShowDialog
. 阅读以下链接备注部分的第二点
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.form.close?view=netframework-4.7.2
在这种情况下,不会释放表单。
您已经使用 ShowDialog 显示了表单。在这些情况下,您将需要手动调用 Dispose 以将表单的所有控件标记为垃圾回收。
或者,如果您想要模态对话框,则通过处理事件来清理上下文closing
,如果您在关闭父窗体之前对其他控件没有问题。
推荐阅读
- database - 确保集合中存在文档数组
- react-native - React-Native HighCharts 提升模块的使用
- javascript - 在 Angular 中使用 Google One Tap
- c++ - 在kali系统中如何解决c语言这个错误?
- r - 放大使用 ggplotly 生成的交互式绘图时的对象大小
- json - 如何在 Azure 流分析中展平嵌套的 json 数据
- linux - 基于多个条件的 DNS 转发(Linux Bind)
- python - 以 sr.Microphone() 作为源不工作
- android - Koin 共享依赖关系范围为嵌套图
- node.js - 使用 loopback4 解析 xml 请求正文