Ok, meine "Lösung" sieht jetzt so aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84:
| public class DbContextLocator { public static DbContextLocator Instance { get; } = new DbContextLocator();
private readonly ICollection<DbContext> _registeredContexts; private readonly IDictionary<object, DbContext> _entityContexts; private readonly IDictionary<DbSet, NotifyCollectionChangedEventHandler> _dbSetLocalChangedHandler;
private DbContextLocator() { _registeredContexts = new List<DbContext>(); _entityContexts = new ConcurrentDictionary<object, DbContext>(); _dbSetLocalChangedHandler = new ConcurrentDictionary<DbSet, NotifyCollectionChangedEventHandler>(); }
public TDbContext FindDbContext<TDbContext>(object entity) where TDbContext : DbContext { return FindDbContext(entity) as TDbContext; } public DbContext FindDbContext(object entity) { return _entityContexts.ContainsKey(entity) ? _entityContexts[entity] : null; }
public void RegisterContext(DbContext context) { foreach (var dbSet in GetDbSets(context)) AddDbSetLocalChangedHandler(dbSet, context);
lock (_registeredContexts) { if (!_registeredContexts.Contains(context)) _registeredContexts.Add(context); } } public void DeregisterContext(DbContext context) { foreach (var dbSet in GetDbSets(context)) { var observableCollection = dbSet.Local as INotifyCollectionChanged;
if (_dbSetLocalChangedHandler.ContainsKey(dbSet)) observableCollection.CollectionChanged -= _dbSetLocalChangedHandler[dbSet];
foreach (var entity in dbSet) _entityContexts.Remove(entity); }
lock (_registeredContexts) _registeredContexts.Remove(context); }
private void AddDbSetLocalChangedHandler(DbSet dbSet, DbContext context) { var observableCollection = dbSet.Local as INotifyCollectionChanged;
if (!_dbSetLocalChangedHandler.ContainsKey(dbSet)) { _dbSetLocalChangedHandler.Add(dbSet, (sender, e) => { foreach (var oldEntity in e.OldItems?.Cast<object>() ?? new object[0]) _entityContexts.Remove(oldEntity);
foreach (var newEntity in e.NewItems?.Cast<object>() ?? new object[0]) { if (!_entityContexts.ContainsKey(newEntity)) _entityContexts.Add(newEntity, context); } });
observableCollection.CollectionChanged += _dbSetLocalChangedHandler[dbSet]; } } private static IEnumerable<DbSet> GetDbSets(DbContext context) { var objectContext = ((IObjectContextAdapter)context).ObjectContext; var container = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace);
return from entitySet in container.EntitySets let entityType = Type.GetType(entitySet.ElementType.FullName) select context.Set(entityType); } } |
Was ich im Prinzip mache, ist folgendes:
Vom DbContext alle DbSets abfragen und für jedes DbSet auf die Local-Property ein CollectionChanged-Handler registrieren.
So kann ich für jedes hinzugefügte oder entfernte Entity-Objekt den aktuellen DbContext im Dictionary bereit halten.
In jeder Entity, die das braucht, muss ich dann noch einen Konstruktor-Parameter für den DbContext hinzufügen, damit ich den beim neu erstellen einer Entity mit geben kann.
Damit EF damit arbeiten kann, brauchts aber noch einen parameterlosen Konstruktor, aber der kann auch private sein.
Das funktioniert, zumindest soweit ich das getestet habe, aber es wirkt für mich wie eine ziemlich wackelige Krücke.
Wenn jemand eine bessere Idee hat, wäre ich da sehr dankbar.