25

I want to refresh all entities of my DbContext without recreating it, I tried the following and none of them make sense:

var context = ((IObjectContextAdapter)myDbContext).ObjectContext;

var refreshableObjects = (from entry in context.ObjectStateManager.GetObjectStateEntries(
                                   EntityState.Added
                                   | EntityState.Deleted
                                   | EntityState.Modified
                                   | EntityState.Unchanged)
                          where entry.EntityKey != null
                          select entry.Entity);

context.Refresh(RefreshMode.StoreWins, refreshableObjects);
//.......................................................................
foreach (var entry in this.Orm.ChangeTracker.Entries())
{
    entry.State = EntityState.Unchanged;
}
this.Orm.ChangeTracker.DetectChanges();

And the only one which refreshes my DbContext:

foreach (var i in this.Orm.ChangeTracker.Entries())
    i.Reload();

But it's too slow. Can you help me choosing the right way?

Mohsen
  • 4,000
  • 8
  • 42
  • 73
  • 1
    Did you try context.Refresh(RefreshMode, Entity) and see in the debugger and sql monitor if it is really updated? – yonexbat Aug 11 '13 at 08:58
  • @yonexbat:I manually changed the data in sql and called the `context.Refresh(RefreshMode, Entity)` but non of changes updated, and done the same scenario with `i.Reload();` and all changes updated in my `DbContext`. – Mohsen Aug 11 '13 at 09:12

5 Answers5

41

I just found that the Enumerable result should be evaluated because the Refresh method gets it as object and doesn't evaluate it.

var context = ((IObjectContextAdapter)myDbContext).ObjectContext;
var refreshableObjects = (from entry in context.ObjectStateManager.GetObjectStateEntries(
                                           EntityState.Added
                                           | EntityState.Deleted
                                           | EntityState.Modified
                                           | EntityState.Unchanged)
                          where entry.EntityKey != null
                          select entry.Entity).ToList();

context.Refresh(RefreshMode.StoreWins, refreshableObjects);

And I prefer the following:

var refreshableObjects = myDbContext.ChangeTracker.Entries().Select(c=>c.Entity).ToList();
context.Refresh(RefreshMode.StoreWins, refreshableObjects);
Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
Mohsen
  • 4,000
  • 8
  • 42
  • 73
  • 2
    Using your method, I got: The element at index 0 in the collection of objects to refresh is in the added state. Objects in this state cannot be refreshed. – isti_spl Feb 05 '14 at 20:11
  • 2
    @isti_spl:u'd better rollback before referesh `if (entry.State==EntityState.Added) entry.State = EntityState.Detached;//...` – Mohsen Feb 06 '14 at 06:53
  • 1
    you save my day Mohsen :D – senzacionale Nov 03 '14 at 19:26
  • 1
    I get the same as @isti_spl but I'm unclear what is the resolution. How do we handle the Added state? – YeahStu Sep 02 '15 at 14:19
  • 1
    @YeahStu you simply don't get remove the EntityState.Added from the above code. It doesn't make sense to refresh entities from store that are being added. They don't exist on the store yet. – Christian Rodriguez Jun 02 '16 at 11:07
14

I checked this and id works fine:

//Search
Box box = dbContext.Boxes.FirstOrDefault(x => x.BoxId == 45);

//breakpoint here, change Name of Box by sql management studio

//Refresh
var context = ((IObjectContextAdapter)dbContext).ObjectContext;
context.Refresh(System.Data.Entity.Core.Objects.RefreshMode.StoreWins, box);

//Check refresh and if it is in context
box = dbContext.Boxes.FirstOrDefault(x => x.BoxId == 45);

Are you sure it is the same db-context?

Community
  • 1
  • 1
yonexbat
  • 2,902
  • 2
  • 32
  • 43
4
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace System.Data.Entity
{
    public static class DbContextExtensions
    {
        /// <summary>
        /// Refresh non-detached entities
        /// </summary>
        /// <param name="dbContext">context of the entities</param>
        /// <param name="refreshMode">store or client wins</param>
        /// <param name="entityType">when specified only entities of that type are refreshed. when null all non-detached entities are modified</param>
        /// <returns></returns>
        public static DbContext RefreshEntites(this DbContext dbContext, RefreshMode refreshMode, Type entityType)
        {
            //https://christianarg.wordpress.com/2013/06/13/entityframework-refreshall-loaded-entities-from-database/
            var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
            var refreshableObjects = objectContext.ObjectStateManager
                .GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
                .Where(x => entityType == null || x.Entity.GetType() == entityType)
                .Where(entry => entry.EntityKey != null)
                .Select(e => e.Entity)
                .ToArray();

            objectContext.Refresh(RefreshMode.StoreWins, refreshableObjects);

            return dbContext;
        }

        public static DbContext RefreshAllEntites(this DbContext dbContext, RefreshMode refreshMode)
        {
            return RefreshEntites(dbContext: dbContext, refreshMode: refreshMode, entityType: null); //null entityType is a wild card
        }

        public static DbContext RefreshEntites<TEntity>(this DbContext dbContext, RefreshMode refreshMode)
        {
            return RefreshEntites(dbContext: dbContext, refreshMode: refreshMode, entityType: typeof(TEntity));
        }
    }
}
Sean M
  • 616
  • 6
  • 16
4

In some cases, if a collection has been updated by a third party app, the collection may not be reloaded when refreshing the collection's object.

I had the case where I had an object A with a one to many relashionship to an object B.

Application 1 loads an object A with A.ListB empty. Application 2 fills the A.ListB collection. Application 1 reloads the object A.

With the solution above, A.ListB remains empty. I had to reload the collection A.ListB explicitly.

Here is a generic way to have all collections reloaded:

var context = ((IObjectContextAdapter)this).ObjectContext;

// detach all added entities
ChangeTracker.Entries().Where(e => e.State == EntityState.Added).ToList().ForEach(e => e.State = EntityState.Detached);

// select entities
var refreshableObjects = ChangeTracker.Entries().Select(e => e.Entity).ToList();

// refresh each refreshable object
foreach (var @object in refreshableObjects)
{
    // refresh each collection of the object
    context.ObjectStateManager.GetRelationshipManager(@object).GetAllRelatedEnds().Where( r => r.IsLoaded).ToList().ForEach( c => c.Load() );

    // refresh the object
    context.Refresh(RefreshMode.StoreWins, @object);
}
Anthony Brenelière
  • 60,646
  • 14
  • 46
  • 58
1

I had a trigger after insert in the database and I was working inside a transaction, so I needed to get the new values generated by the trigger in the same context. This worked for me:

using (var ctx = new context())
{
    ctx.Connection.Open();
    ctx.Transaction = ctx.Connection.BeginTransaction();

    ctx.Entities.InsertOnSubmit(itemDB);
    ctx.SubmitChanges();
    ctx.Refresh(RefreshMode.OverwriteCurrentValues, itemDB);

    Model newModel = itemDB.ToModel();

    ctx.Transaction.Commit();
    return newModel;
}
catch (Exception ex)
{
    ctx.Transaction.Rollback();
}