C# Entity Framework泛型类:实现所有子实体重新加载
Solution for Reloading Nested Entities in Entity Framework 6
Since you’ve got a multi-level one-to-many hierarchy (tblProjects → tblLines → tblGroups → tblStations...) where all entities inherit from TblBase, we can build a generic reloading utility that recursively refreshes any entity along with all its nested child collections. This leverages EF6's context entry APIs and works seamlessly with your base class structure.
Generic Entity Reloader Implementation
Here's a static extension class that adds reloading functionality to your DbContext, tailored to your inherited TblBase entities:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Reflection; public static class EntityReloader { /// <summary> /// Reloads a single entity and all its nested child collections recursively /// </summary> /// <typeparam name="TEntity">Type of entity (must inherit from TblBase)</typeparam> /// <param name="context">Your EF DbContext</param> /// <param name="entity">Entity to reload</param> public static void ReloadWithChildren<TEntity>(this DbContext context, TEntity entity) where TEntity : TblBase { if (entity == null) return; // Refresh the parent entity itself var entityEntry = context.Entry(entity); entityEntry.Reload(); // Get all one-to-many navigation properties (ICollection<T> types) var childCollectionProps = entityEntry.NavigationProperties .Where(np => typeof(ICollection<>).IsAssignableFrom(np.PropertyType)) .Select(np => np.Name); foreach (var propName in childCollectionProps) { // Load the child collection if it isn't already loaded entityEntry.Collection(propName).Load(); // Get the collection instance and recursively reload each child var childEntities = entityEntry.Property(propName).CurrentValue as IEnumerable<TblBase>; if (childEntities == null) continue; foreach (var child in childEntities) { context.ReloadWithChildren(child); } } } /// <summary> /// Reloads a collection of entities and all their nested child collections /// </summary> /// <typeparam name="TEntity">Type of entity (must inherit from TblBase)</typeparam> /// <param name="context">Your EF DbContext</param> /// <param name="entities">Collection of entities to reload</param> public static void ReloadWithChildren<TEntity>(this DbContext context, IEnumerable<TEntity> entities) where TEntity : TblBase { if (entities == null) return; foreach (var entity in entities) { context.ReloadWithChildren(entity); } } }
How It Works
- Base Entity Reload: First, it refreshes the parent entity using
DbEntityEntry.Reload(), pulling the latest database data into your entity instance. - Child Collection Detection: It identifies all
ICollection<T>navigation properties (these are the one-to-many child sets in your hierarchy, liketblProjects.LinesortblLines.Groups). - Recursive Child Reload: For each child collection, it loads the data (if not already loaded) and then recursively calls
ReloadWithChildrenon every child entity—ensuring every level of your hierarchy gets refreshed. - INotifyPropertyChanged Compatibility: Since your
TblBaseimplementsINotifyPropertyChanged, property setters will trigger change notifications automatically after reloading, so UI bindings update without extra work.
Usage Examples
Reload a Single Project and All Its Children
using (var context = new YourDbContext()) { // Fetch a project (could be any entity in your hierarchy) var targetProject = context.tblProjects.FirstOrDefault(p => p.ID == 42); // Refresh the project + all lines, groups, stations, etc. context.ReloadWithChildren(targetProject); }
Reload a Collection of Entities
using (var context = new YourDbContext()) { var projectsToRefresh = context.tblProjects.Where(p => p.COID == 5).ToList(); // Refresh all projects in the list and their nested children context.ReloadWithChildren(projectsToRefresh); }
Key Notes
- Navigation Property Filtering: The code targets all
ICollection<T>navigation properties. If you have non-navigationICollectionproperties, add a filter (e.g., checknp.IsNavigationor use a custom attribute to mark navigation properties). - Performance Considerations: For large datasets or deep hierarchies, this results in multiple database queries (N+1 pattern). For initial loading, use
Includechains (e.g.,context.tblProjects.Include(p => p.Lines.Select(l => l.Groups.Select(g => g.Stations)))), but this reloader is ideal for refreshing existing entity instances. - Context Lifecycle: Use the same
DbContextinstance that originally fetched the entities—EF6 tracks entities per context, so reloading with a different context won’t update your existing instances.
内容的提问来源于stack exchange,提问作者PigSpider
相关产品推荐
相关产品推荐

