Example #1
0
        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;
                }
            }
        }
Example #2
0
        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);
            }
        }