【问题标题】:How can I tell Entity Framework to save changes only for a specific DbSet?如何告诉 Entity Framework 仅保存特定 DbSet 的更改?
【发布时间】:2015-10-29 00:14:17
【问题描述】:

假设我在单个 DbContext 中修改来自不同 DbSet 的实体。

在调用 SaveChanges() 时,我如何告诉 Entity Framework 仅保存特定 DbSet 的更改?

【问题讨论】:

  • 您不需要其他实体更改或者您想要它们?
  • 我想要它们,但稍后(我无法更改更改方式/顺序)。
  • 您可以拒绝其他DbSet 更改并仅保存您特定的DbSet 更改,但这样您将丢失其他DbSet 更改。
  • 永久或仅用于该交易?你能告诉我怎么做吗?

标签: c# .net entity-framework


【解决方案1】:

理想情况下,您只需修改要更改的实体,然后调用SaveChanges(),然后修改其他实体。但是,如果这不可能,我会添加一个看起来像这样的SaveChanges() 的重载。

public int SaveChanges<TEntity>() where TEntity : class
{
    var original = this.ChangeTracker.Entries()
                .Where(x => !typeof(TEntity).IsAssignableFrom(x.Entity.GetType()) && x.State != EntityState.Unchanged)
                .GroupBy(x => x.State)
                .ToList();

    foreach(var entry in this.ChangeTracker.Entries().Where(x => !typeof(TEntity).IsAssignableFrom(x.Entity.GetType())))
    {
        entry.State = EntityState.Unchanged;
    }

    var rows = base.SaveChanges();

    foreach(var state in original)
    {
        foreach(var entry in state)
        {
            entry.State = state.Key;
        }
    }

    return rows;
}

最初,您会找到所有状态未更改的实体并保存它们的条目。然后,您将每个不属于您的类型TEntity 的实体的状态设置为不变。然后调用base.SaveChanges() 将所有更改保存到您的类型的实体。

然后,通过循环访问保存的条目,您可以将它们的原始状态重置回它们。这样,您可以捕获所有不属于您的类型的添加/更新/删除,并恢复它们,以便下次调用 SaveChanges() 时不会丢失它们的更改。

【讨论】:

  • 我认为这会通过一些小的变化来解决问题,例如,当使用代理创建对象时,这个标准 `x.Entity.GetType() != typeof(TEntity)` 不会工作。但我仍然认为使用多个工作单元是更好的选择:) +1
  • 我同意。只是创建一个新的上下文要安全得多,但是以你不应该的方式弄乱 EF 对我来说有点奇怪。 :) 我会将类型检查更改为您所拥有的。
【解决方案2】:

在使用下面的代码之前,您应该知道是否只想保存一组特定的实体,那么这意味着您应该为您的工作单元使用不同的数据库上下文实例。

但使用此代码,您可以拒绝除YourSpecialEntity 之外的所有实体的更改:

db.ChangeTracker.Entries()
                .Where(x => x.State == EntityState.Modified &&
                            !typeof(YourSpecialEntity).IsAssignableFrom(x.Entity.GetType()))
                .ToList()
                .ForEach(entry => {
                    entry.CurrentValues.SetValues(entry.OriginalValues);
                });

db.SaveChanges();

我想 db 是你的 dbcontext 的一个实例。

【讨论】:

  • 我明白了,所以这会重置其他实体的值。如果我保留对已修改条目的引用,仅将状态更改为“未修改”,保存当前集合的更改,然后将引用的状态更改回“已修改”,该怎么办?
  • 你可以做这样的工作,但它有点难闻。我认为使用多个工作单元的提议要好得多。
【解决方案3】:

我是 EF 新手,遇到了同样的问题。在我的存储程序中,例如,我只为新股票添加 articleId 和 OwnerId,因为我认为我的 mvc 表单中不需要隐藏字段。起初 EF 在文章和客户数据库中创建了新条目,但我只想在股票表中插入一个新项目。 所以解决方案非常简单: 对于您知道不想保存的所有实体,请输入以下内容:

           //prevent Owner to be saved (again)
            db.Entry(stockItem.Owner).State = EntityState.Unchanged;

          //prevent article to be saved (again)  
           db.Entry(stockItem.ArticleItem).State = EntityState.Unchanged;

            db.Stocks.Add(stockItem);

           //now just the properties (-> dbset of the stockItem get´s saved)
            await db.SaveChangesAsync();
            return RedirectToAction("Index");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多