Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell Entity Framework to save changes only for a specific DbSet?

Let's say I modify entities from different DbSets within a single DbContext.

How can I tell Entity Framework, when calling SaveChanges(), to save changes only for a specific DbSet?

like image 235
Dan Avatar asked Oct 29 '15 00:10

Dan


Video Answer


3 Answers

Ideally, what you would do is just modify the entities you want to change, then call SaveChanges() then modify the other entities. However, if that is not possible I would add an overload of SaveChanges() that looks like this.

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;
}

Initially you find all entities whose state is not unchanged and save their entry. Then you set the state of every entity that isn't of your type TEntity and set their state to unchanged. Then call the base.SaveChanges() to save all changes to entities of your type.

Then, by looping through the saved entries, you can reset their original states back to them. This way you catch all adds/updates/deletes that aren't of your type, and restore them so that the next call to SaveChanges() doesn't lose their changes.

like image 115
Bradford Dillon Avatar answered Oct 13 '22 01:10

Bradford Dillon


Before using the below code, you should know if you want to save only a specific set of entities, then it means you should use different instance of your db context for that unit of your work.

But using this code you can reject changes of all entities except 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();

I suppose db is an instance of your dbcontext.

like image 20
Reza Aghaei Avatar answered Oct 13 '22 01:10

Reza Aghaei


I am new to EF and I had the same problem. In my storage program i e.g sumit only articleId and OwnerId for a new stock because i see no need for hidden fields in my mvc-form. At first EF created new entries in article and customer database, but i only wanted to insert a new item in the stocks table. So the solution is quite simple: For all entities you know you don´t want to save them type this:

           //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");
like image 27
Matthias Krüger Avatar answered Oct 13 '22 00:10

Matthias Krüger