新对象与数据上下文分离

我在后台工作程序中添加了一个新对象,该新对象已成功添加,但是如果尝试删除它,则会出现错误,因为新对象已与数据上下文分离。

后台工作者工作事件

private void _anotherThread_DoWork(object sender,DoWorkEventArgs e)
    {
        testdbEntities context = new testdbEntities();

        _item = new item();
        this.txbItemName.Dispatcher.Invoke(new action(delegate () { _item.name = this.txbItemName.Text; }));

        context.item.Add(_item);
        Application.Current.Dispatcher.BeginInvoke(new action(() => this.ocItems.Add(_item)));

        context.SaveChanges();
    }

删除按钮(在主线程上) ,如果我附加了一个新对象,它将起作用

private void btnDelete_Click(object sender,RoutedEventArgs e)
    {
        Item _selectedItem = (Item)lbItems.SelectedItem;

        if (_context.Entry(_selectedItem).State == EntityState.Detached)
            _context.Item.Attach(_selectedItem);

        _context.Item.Remove(_selectedItem);
        _context.SaveChanges();
    }

我的问题是为什么新对象未附加到数据上下文?我应该在后台工作程序中添加所有新对象吗?

谢谢

k12play 回答:新对象与数据上下文分离

我强烈建议使用实体,尤其是控件绑定中的跟踪实体。被跟踪实体的生存期仅应与DbContext一样长,并且您创建的任何DbContext都应具有定义的生存期范围。 (处理它们)

因此,在您的后台工作中,新建DbContext的范围应在using块内,以确保将其丢弃。

private void _anotherThread_DoWork(object sender,DoWorkEventArgs e)
{
    using(testdbEntities context = new testdbEntities())
    {
        _item = new item();
        this.txbItemName.Dispatcher.Invoke(new Action(delegate () { _item.name = this.txbItemName.Text; }));

        context.item.Add(_item);
        Application.Current.Dispatcher.BeginInvoke(new Action(() => this.ocItems.Add(_item)));

        context.SaveChanges();
        context.Detach(_item); 
    }
}

然后,当您使用“删除”按钮时,如果要处理长期存在的DbContext(_context),请检查上下文以查看是否已跟踪该实体,如果没有,请附加该实体(或其代理) )并执行删除操作。如果已被跟踪,则删除被跟踪的一个:

private void btnDelete_Click(object sender,RoutedEventArgs e)
{
    Item _selectedItem = (Item)lbItems.SelectedItem;

    Item existingItem = _context.Item.Local.SingleOrDefault(x => x.ItemId == _selectedItem.ItemId);
    if (existingItem != null)
        _context.Item.Remove(existingItem);
    else
    {
        _context.Item.Attach(_selectedItem);
        _context.Item.Remove(_selectedItem);
    }
    _context.SaveChanges();
}

检查.Local不会访问数据库,它只是在寻找该ID的跟踪实体引用。如果找到一个,我们将其删除。如果没有,我们可以将其附加并删除以发出Delete。

长期存在的DbContext可能会导致您出现问题,因为通过各种操作,可能已经跟踪了具有列表项ID的实体,因此使用存储在List控件中的陈旧副本的附加/分离状态将不会造成麻烦”要可靠。

如果列表项返回要删除的实体的ID而不是未跟踪的实体引用,您仍然可以有效地删除该实体:

private void btnDelete_Click(object sender,RoutedEventArgs e)
{
    int itemId = lbItems.SelectedItem.ItemId; // Where a simple view model was put in the SelectedItem,not an entity.

    Item existingItem = _context.Item.Local.SingleOrDefault(x => x.ItemId == itemId);
    if (existingItem != null)
        _context.Item.Remove(existingItem);
    else
    { 
        var tempItem = new Item { ItemId = itemId }; 
        _context.Item.Attach(tempItem);
        _context.Item.Remove(tempItem);
    }
    _context.SaveChanges();
}

没什么大不同,但是删除了您的列表项实际上包含一个完整实体的假设。列表视图模型也可以比整个实体紧凑得多,所需的内存和加载时间更少。处理附加和分离的实体的风险是,如果已经跟踪了该ID的另一个实体(由于编辑等),并且对于诸如编辑之类的操作,这些实体仍然过时,则仍然需要根据上下文评估这些实体。 。其他应用程序/用户/进程可能已经更新了实体背后的数据。通过附加并执行诸如编辑和保存更改的操作,该实体仅保留该用户的最后一个已知状态,该状态可以并且将覆盖其他用户所做的更改。处理并发编辑时,最好加载该实体,检查行的版本或时间戳以查看自上次检索以来是否已对其进行修改,并处理场景是否存在。您还可能遇到以下问题:自从您的当前会话检索到基础记录以来,该基础记录可能已被删除,在这种情况下,附加,更新和SaveChanges会导致“预期为1,发现为0”错误或类似的错误。 (不确定,但是在“删除”场景中也可能发生这种情况。)

本文链接:https://www.f2er.com/3164645.html

大家都在问