为DataGridView保持DbContext打开

时间:2017-08-14 20:41:34

标签: c# winforms entity-framework datagridview savechanges

我有一个DataGridView,而DataGridView的DataSource是我通过context.Person.Local.ToBindingList()从实体框架(V6)获得的BindingList。 在我将DataSource设置为此BindingList之后,我处理了上下文,因为我读到保持上下文打开将是不好的做法。

所以,如果我想添加一个新行,我会点击我将“people”对象数据源拖到我的Windows窗体时创建的BindingNavigator附带的“添加”按钮。 每次我点击“添加”按钮,我都会得到一个异常,告诉我上下文已被处理掉。 使用DataGridView时是否需要始终打开上下文?哦和:DataSource可能会在运行时更改,具体取决于ListBox项的选择。

此外,当已经处理了上下文并且我从DataGridView编辑了一行时,我怎么能找到(在多次更改之后)哪一行发生了变化? 我试着这样做:

foreach(DataGridViewRow row in peopleDataGridView.Rows)
{
    People item = (People)row.DataBoundItem;
    if (item != null)
    {
        db.People.Attach(item);
    }
}
db.SaveChanges();

...但SaveChanges()无法识别任何更改。但是,如果我强制每个附加项目处于“已修改”状态,则它会起作用。但我不想将100个项目更改为“已修改”,如果只有一个实际修改过。

有什么想法吗?

编辑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开始有时根本不显示任何条目。一种奇怪的行为。 我现在做错了什么?

编辑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()方法,它的条目也不会再次重新加载。有没有办法强制重新加载实体?

3 个答案:

答案 0 :(得分:0)

  • 请确保您的商品不是空。

  • 检查您的连接字符串。

并试试这个:

db.People.Add(item);

而不是:

db.People.Attach(item);

答案 1 :(得分:0)

虽然我尽量不让DBContext保持打开很长一段时间,但是对于datagrids你没有太多选择。我将网格的DataSource属性设置为IQueryable<T>,然后所有编辑,删除和添加都由网格和上下文本身处理。只要您想要保留更改,就必须致电dbContext.SubmitChanges()。通过保存RowLeaveRowValidated事件,您可以在用户每次离开行时保存。或者您可以在关闭表单时保存。但是也要确保在关闭表单时调用dbContext.Dispose()

要找出哪些行发生了变化,您可以通过执行以下操作查看返回的ChangeSet

var changes = dbContext.GetChangeSet();
dbContext.SubmitChanges();

答案 2 :(得分:0)

好的,感谢@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();
}
  • 编辑条目
  • 添加新条目
  • 正在删除条目