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.
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.
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 (); } }
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With