Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Refresh Data

I have a datagrid that has a collection bound to it through a BindingSource:

            bsProducts.DataSource = cc.Products.Local.ToBindingList();

One of the entities in the Grid is being edited (and saved) in a different form and i would like to refresh the grid on this form, now I tried to reload the entity, reload the whole local context but for some reason it is not reading the related sub entities. Now when I close the whole form and open it up again all is being read.

To refresh the entity i'm using the following code:

        await cc.Entry<Product>(product).ReloadAsync();

But that will not load any related entities that are bound to the Product Entity. I have retried to update the BindingSource afterwards but no luck.

like image 720
Martin Avatar asked Nov 24 '15 12:11

Martin


People also ask

How to refresh an entity in a context?

The best way to refresh entities in your context is to dispose your context and create a new one. If you really need to refresh some entity and you are using Code First approach with DbContext class, you can use.

How to reload a specific entity in Entity Framework?

If you want to reload specific entities, with the DbContextApi, RX_DID_RX already gave you the answer. If you are using Entity Framework 4.1+ (EF5, or EF 6 probably), DbContext API: public void RefreshAll () { foreach (var entity in ctx.ChangeTracker.Entries ()) { entity.Reload (); } }

What is the use of refresh () method in Salesforce?

This method has the dual purpose of allowing objects in the object context to be refreshed with data from the data source, and being the mechanism by which conflicts can be resolved. For more information, see Saving Changes and Managing Concurrency.

What is the purpose of the object context refresh method?

This method has the dual purpose of allowing objects in the object context to be refreshed with data from the data source, and being the mechanism by which conflicts can be resolved. For more information, see Saving Changes and Managing Concurrency. The order in which objects are refreshed is nondeterministic.


1 Answers

I happened to be working on a "visitor" for an entity object graph. Seeing your question I gave it the last touch to make it useful in your case (and many others). It's not a real visitor as in the well-known visitor pattern, but it does basically the same thing: it traverses an object graph and executes some action for each entity it encounters.

Using this method you can simply call ...

cc.Visit(product, e => cc.Entry(e).Reload());

... and you'll see that product and all adhering objects are reloaded.

Here is the code:

public static class DbContextExtensions
{
    public static void Visit(this DbContext context, object entity, Action<object> action)
    {
        Action<object, DbContext, HashSet<object>, Action<object>> visitFunction = null; // Initialize first to enable recursive call.
        visitFunction = (ent, contxt, hashset, act) =>
          {
              if (ent != null && !hashset.Contains(ent))
              {
                  hashset.Add(ent);
                  act(ent);
                  var entry = contxt.Entry(ent);
                  if (entry != null)
                  {
                      foreach (var np in contxt.GetNavigationProperies(ent.GetType()))
                      {
                          if (np.ToEndMember.RelationshipMultiplicity < RelationshipMultiplicity.Many)
                          {
                              var reference = entry.Reference(np.Name);
                              if (reference.IsLoaded)
                              {
                                  visitFunction(reference.CurrentValue, contxt, hashset, action);
                              }
                          }
                          else
                          {
                              var collection = entry.Collection(np.Name);
                              if (collection.IsLoaded)
                              {
                                  var sequence = collection.CurrentValue as IEnumerable;
                                  if (sequence != null)
                                  {
                                      foreach (var child in sequence)
                                      {
                                          visitFunction(child, contxt, hashset, action);
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          };
        visitFunction(entity, context, new HashSet<object>(), action);
    }

    // Get navigation properties of an entity type.
    public static IEnumerable<NavigationProperty> GetNavigationProperies(this DbContext context, Type type)
    {
        var oc = ((IObjectContextAdapter)context).ObjectContext;
        var objectType = ObjectContext.GetObjectType(type); // Works with proxies and original types.

        var entityType = oc.MetadataWorkspace.GetItems(DataSpace.OSpace).OfType<EntityType>()
                           .FirstOrDefault(et => et.Name == objectType .Name);
        return entityType != null
            ? entityType.NavigationProperties
            : Enumerable.Empty<NavigationProperty>();
    }
}

It is a recursive function wrapped in an extension method. I wrapped the recursive part so I could send a local HashSet down the graph that collects visited entities and thereby prevents circular references. Basically the function applies the specified action to the entity, then finds its navigation properties – which can be references or collections – gets their values (CurrentValue) and then calls itself for these values.

Notice that I also check if the navigation properties are loaded. Without this, an endless chain of lazy loading may get triggered.

Also notice that this fires one query for each entity in the graph. This is not a suitable method for large object graphs. If you want to refresh large amounts of data you should take a different approach, preferably create a new context.

like image 151
Gert Arnold Avatar answered Sep 20 '22 11:09

Gert Arnold