为 DataGridView 保持 DbContext 打开
Keep DbContext open for DataGridView
我有一个 DataGridView,DataGridView 的数据源是我通过 context.Person.Local.ToBindingList() 从 Entity Framework (V6) 获得的一个 BindingList。
在我将 DataSource 设置为此 BindingList 后,我处理了上下文,因为我读到保持上下文打开是不好的做法。
因此,如果我想添加一个新行,我会单击 "add" 按钮,该按钮随 BindingNavigator 一起出现,当我将 "people" 对象数据源拖到我的 Windows表格。
每次单击 "add" 按钮时,都会出现一个异常,告诉我上下文已被释放。
使用 DataGridView 时是否需要一直保持上下文打开?哦还有:根据列表框项的选择,数据源可能会在运行时发生变化。
此外,当上下文已被处理并且我从 DataGridView 编辑了一行时,我如何才能找出(在多次更改之后)哪一行发生了更改?
我尝试这样做:
foreach(DataGridViewRow row in peopleDataGridView.Rows)
{
People item = (People)row.DataBoundItem;
if (item != null)
{
db.People.Attach(item);
}
}
db.SaveChanges();
...但 SaveChanges() 未识别出任何更改。但是,如果我强制每个附加项目都处于 "modified" 状态,它就会起作用。但是我不想将 100 个项目更改为 "modified",如果实际上只有一个被修改的话。
有什么想法吗?
编辑 1
哦,好吧,所以我更改了我的代码以始终保持上下文打开(或者至少只要显示表单)。
现在,我 运行 遇到了一个不同的问题(人们可能有很多工作):
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
//jobBindingSource.Clear(); this caused another error at runtime...
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
绑定到此 jobBindingSource 实例的 DataGridView 显示一个人的正确工作,但 此外 先前选择的人的工作。我尝试清除 () 条目,但如果我这样做并两次单击同一个人,则 datagridview 开始有时根本不显示任何条目。 st运行ge 行为。
我现在做错了什么?
编辑 2
好的...我自己找到了解决方案。但我拒绝接受这是正确的做法:
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
db.Dispose();
db = new PeopleJobsEntities();
db.People.Attach(p);
db.Entry(p).Collection(person => person.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
只有当我处理上下文并重新打开它时,整个过程才有效。原因是如果我清除本地缓存(db.Job.Local),即使我使用 Load() 方法也不会重新加载它的条目。有什么方法可以强制重新加载实体吗?
请确定您的商品是否为空。
检查您的连接字符串。
然后,试试这个:
db.People.Add(item);
而不是:
db.People.Attach(item);
虽然我尽量不让 DBContext 长时间打开,但对于数据网格,您别无选择。我将网格的 DataSource
属性 设置为 IQueryable<T>
,然后所有编辑、删除和添加都由网格和上下文本身处理。只要您想保留更改,您只需调用 dbContext.SubmitChanges()
即可。每次用户离开行时,您都可以保存 RowLeave
或 RowValidated
事件。或者您可以在关闭表单时保存。但也要确保在关闭表单时也调用 dbContext.Dispose()
。
要找出更改的行,您可以查看通过执行以下操作返回的 ChangeSet
:
var changes = dbContext.GetChangeSet();
dbContext.SubmitChanges();
好的,感谢@jaredbaszler,我想出了这个适合我的解决方案。
我决定让 DbContext 一直保持活动状态。为了清除本地缓存,我在循环中分离了每个实体。我认为这是一种非常令人作呕的方式。 一定有更好的方法...
这是我的:
PeopleJobsEntities db;
public FormTest()
{
InitializeComponent();
db = new PeopleJobsEntities();
db.Database.Log = Console.Write;
db.People.Load();
List<People> peoplelist = db.People.Local.ToList();
listBox1.DataSource = peoplelist;
}
private void FormTest_FormClosing(object sender, FormClosingEventArgs e)
{
if (db != null)
db.Dispose();
}
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
List<Job> oldlist = db.Job.Local.ToList();
foreach (Job j in oldlist)
{
db.Entry(j).State = EntityState.Detached;
}
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
private void jobBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach(DataGridViewRow row in jobDataGridView.Rows)
{
if(row != null && row.DataBoundItem != null)
{
Job j = (Job)row.DataBoundItem;
if(db.Entry(j).State == EntityState.Added)
{
if(j.People.Count == 0)
{
People people = (People)listBox1.SelectedItem;
if (people != null)
j.People.Add(people);
}
}
}
}
db.SaveChanges();
}
- 编辑条目有效
- 添加新条目有效
- 删除条目有效
我有一个 DataGridView,DataGridView 的数据源是我通过 context.Person.Local.ToBindingList() 从 Entity Framework (V6) 获得的一个 BindingList。 在我将 DataSource 设置为此 BindingList 后,我处理了上下文,因为我读到保持上下文打开是不好的做法。
因此,如果我想添加一个新行,我会单击 "add" 按钮,该按钮随 BindingNavigator 一起出现,当我将 "people" 对象数据源拖到我的 Windows表格。 每次单击 "add" 按钮时,都会出现一个异常,告诉我上下文已被释放。 使用 DataGridView 时是否需要一直保持上下文打开?哦还有:根据列表框项的选择,数据源可能会在运行时发生变化。
此外,当上下文已被处理并且我从 DataGridView 编辑了一行时,我如何才能找出(在多次更改之后)哪一行发生了更改? 我尝试这样做:
foreach(DataGridViewRow row in peopleDataGridView.Rows)
{
People item = (People)row.DataBoundItem;
if (item != null)
{
db.People.Attach(item);
}
}
db.SaveChanges();
...但 SaveChanges() 未识别出任何更改。但是,如果我强制每个附加项目都处于 "modified" 状态,它就会起作用。但是我不想将 100 个项目更改为 "modified",如果实际上只有一个被修改的话。
有什么想法吗?
编辑 1 哦,好吧,所以我更改了我的代码以始终保持上下文打开(或者至少只要显示表单)。 现在,我 运行 遇到了一个不同的问题(人们可能有很多工作):
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
//jobBindingSource.Clear(); this caused another error at runtime...
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
绑定到此 jobBindingSource 实例的 DataGridView 显示一个人的正确工作,但 此外 先前选择的人的工作。我尝试清除 () 条目,但如果我这样做并两次单击同一个人,则 datagridview 开始有时根本不显示任何条目。 st运行ge 行为。 我现在做错了什么?
编辑 2 好的...我自己找到了解决方案。但我拒绝接受这是正确的做法:
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
db.Dispose();
db = new PeopleJobsEntities();
db.People.Attach(p);
db.Entry(p).Collection(person => person.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
只有当我处理上下文并重新打开它时,整个过程才有效。原因是如果我清除本地缓存(db.Job.Local),即使我使用 Load() 方法也不会重新加载它的条目。有什么方法可以强制重新加载实体吗?
请确定您的商品是否为空。
检查您的连接字符串。
然后,试试这个:
db.People.Add(item);
而不是:
db.People.Attach(item);
虽然我尽量不让 DBContext 长时间打开,但对于数据网格,您别无选择。我将网格的 DataSource
属性 设置为 IQueryable<T>
,然后所有编辑、删除和添加都由网格和上下文本身处理。只要您想保留更改,您只需调用 dbContext.SubmitChanges()
即可。每次用户离开行时,您都可以保存 RowLeave
或 RowValidated
事件。或者您可以在关闭表单时保存。但也要确保在关闭表单时也调用 dbContext.Dispose()
。
要找出更改的行,您可以查看通过执行以下操作返回的 ChangeSet
:
var changes = dbContext.GetChangeSet();
dbContext.SubmitChanges();
好的,感谢@jaredbaszler,我想出了这个适合我的解决方案。 我决定让 DbContext 一直保持活动状态。为了清除本地缓存,我在循环中分离了每个实体。我认为这是一种非常令人作呕的方式。 一定有更好的方法...
这是我的:
PeopleJobsEntities db;
public FormTest()
{
InitializeComponent();
db = new PeopleJobsEntities();
db.Database.Log = Console.Write;
db.People.Load();
List<People> peoplelist = db.People.Local.ToList();
listBox1.DataSource = peoplelist;
}
private void FormTest_FormClosing(object sender, FormClosingEventArgs e)
{
if (db != null)
db.Dispose();
}
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
List<Job> oldlist = db.Job.Local.ToList();
foreach (Job j in oldlist)
{
db.Entry(j).State = EntityState.Detached;
}
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
private void jobBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach(DataGridViewRow row in jobDataGridView.Rows)
{
if(row != null && row.DataBoundItem != null)
{
Job j = (Job)row.DataBoundItem;
if(db.Entry(j).State == EntityState.Added)
{
if(j.People.Count == 0)
{
People people = (People)listBox1.SelectedItem;
if (people != null)
j.People.Add(people);
}
}
}
}
db.SaveChanges();
}
- 编辑条目有效
- 添加新条目有效
- 删除条目有效