private static IEnumerable <TSource> DetectEnumerableConcurrency <TSource>( IEnumerable <TSource> source, EFCoreDbCommandExecutor executor) { var detector = executor.CurrentDbContext.Context.GetService <IConcurrencyDetector>(); using (var enumerator = source.GetEnumerator()) { KeepOnKeepingOn: var keepKeepingOnKeepingOn = false; using (detector.EnterCriticalSection()) { keepKeepingOnKeepingOn = enumerator.MoveNext(); } if (keepKeepingOnKeepingOn) { yield return(enumerator.Current); goto KeepOnKeepingOn; } } }
private static TSource DetectElementConcurrency <TSource>( Func <TSource> source, EFCoreDbCommandExecutor executor) { var detector = executor.CurrentDbContext.Context.GetService <IConcurrencyDetector>(); using (detector.EnterCriticalSection()) { return(source()); } }
private static object GetEntityUsingStateManager(EFCoreDbCommandExecutor executor, IEntityType entityType, object[] keyValues, object entity, object[] shadowPropertyValues, List <INavigation> includes) { var entry = executor.StateManager.TryGetEntry(entityType.FindPrimaryKey(), keyValues); if (entry == null) { if (shadowPropertyValues.Length == 0) { entry = executor.EntryFactory.Create( executor.StateManager, entityType, entity); } else { entry = executor.EntryFactory.Create( executor.StateManager, entityType, entity, new ValueBuffer(shadowPropertyValues)); } executor.StateManager.StartTracking(entry); entry.MarkUnchangedFromQuery(null); for (var i = 0; i < includes.Count; i++) { entry.SetIsLoaded(includes[i], true); } } else { if (entry.EntityState == EntityState.Detached) { entry.MarkUnchangedFromQuery(null); } for (var i = 0; i < includes.Count; i++) { var include = includes[i]; include.GetSetter().SetClrValue(entry.Entity, include.GetGetter().GetClrValue(entity)); entry.SetIsLoaded(include, true); } } return(entry.Entity); }
private static TService GetServiceForInjection <TService>(EFCoreDbCommandExecutor executor) { var context = executor.CurrentDbContext.Context; if (context is TService service) { return(service); } service = executor.CurrentDbContext.Context.GetInfrastructure().GetService <TService>(); return(service); }
private static object GetEntityUsingIdentityMap(EFCoreDbCommandExecutor executor, IEntityType entityType, object[] keyValues, object entity, object[] shadowPropertyValues, List <INavigation> includes) { if (entity == null) { return(null); } if (!executor.TryGetEntity(entityType, keyValues, out var info)) { Debug.Assert(info.Entity == null); info = new EntityMaterializationInfo { Entity = entity, KeyValues = keyValues, ShadowPropertyValues = shadowPropertyValues, EntityType = entityType, Key = entityType.FindPrimaryKey() }; if (includes.Count != 0) { info.Includes = new HashSet <INavigation>(); } executor.CacheEntity(entityType, keyValues, info); } else if (includes.Count != 0 && info.Includes == null) { info.Includes = new HashSet <INavigation>(); executor.CacheEntity(entityType, keyValues, info); } for (var i = 0; i < includes.Count; i++) { var include = includes[i]; if (!info.Includes.Contains(include)) { FixupNavigation(include, entity, info.Entity); info.Includes.Add(include); } } return(info.Entity); }
private static void HandleEntry <TEntity>(EFCoreDbCommandExecutor executor, ref TEntity entity, IEntityType entityType) { if (entityType == null || !executor.TryGetEntity(entity, entityType, out var info)) { return; } var cached = entity; var entry = executor.StateManager.TryGetEntry(info.Key, info.KeyValues) ?? executor.StateManager.TryGetEntry(entity); if (entry == null) { if (info.ShadowPropertyValues.Length == 0) { entry = executor.EntryFactory.Create( executor.StateManager, info.EntityType, entity); } else { entry = executor.EntryFactory.Create( executor.StateManager, info.EntityType, entity, new ValueBuffer(info.ShadowPropertyValues)); } executor.StateManager.StartTracking(entry); entry.MarkUnchangedFromQuery(null); } else { cached = (TEntity)entry.Entity; if (entry.EntityState == EntityState.Detached) { entry.MarkUnchangedFromQuery(null); } } if (info.Includes != null) { foreach (INavigation include in info.Includes) { entry.SetIsLoaded(include, true); // Test that demonstrates the necessity of fixup: // Include_collection_principal_already_tracked FixupNavigation(include, entity, cached); } } entity = cached; }
private static IEnumerable TrackEntities( IEnumerable source, EFCoreDbCommandExecutor executor, MaterializerAccessorInfo[] accessorInfos) { if (accessorInfos == null) { foreach (var item in IterateSource(source)) { yield return(item); } yield break; } foreach (var item in IterateSource(source)) { var result = item; foreach (var accessorInfo in accessorInfos) { var value = accessorInfo.GetValue(item); if (value == null) { continue; } if (ReferenceEquals(value, item)) { HandleEntry(executor, ref result, accessorInfo.EntityType); continue; } if (value is IQueryable queryable) { var expression = queryable.Expression; if (expression is MethodCallExpression methodCall && methodCall.Method.DeclaringType == typeof(Queryable) && methodCall.Method.Name.Equals(nameof(Queryable.AsQueryable))) { Debug.Assert(methodCall.Arguments.Count == 1); expression = methodCall.Arguments[0]; } if (expression is ConstantExpression constant) { value = constant.Value; } } if (value is IList list) { var i = 0; foreach (var subvalue in TrackEntities(list, executor, accessorInfo.SubAccessors)) { list[i] = subvalue; i++; } continue; } if (value is IEnumerable enumerable) { // The whole point of the IList block above is that // we need to update references to cached entities // within the list. We should make sure that every // materialized IEnumerable is a list. // If there is some kind of issue with entities // not being tracked, uncommenting the below line // might be a good place to start. // Debugger.Break(); foreach (var subvalue in TrackEntities(enumerable, executor, accessorInfo.SubAccessors)) { } continue; } var copy = value; HandleEntry(executor, ref value, accessorInfo.EntityType); if (!ReferenceEquals(copy, value)) { accessorInfo.SetValue?.Invoke(result, value); } } yield return(result); } }