Example #1
0
        private Dictionary <Type, List <string> > GetSets()
        {
            DbContextTypesInitializersPair initializersPair;

            if (!DbSetDiscoveryService._objectSetInitializers.TryGetValue(this._context.GetType(), out initializersPair))
            {
                ParameterExpression               parameterExpression         = Expression.Parameter(typeof(DbContext), "dbContext");
                List <Action <DbContext> >        initDelegates               = new List <Action <DbContext> >();
                Dictionary <Type, List <string> > entityTypeToPropertyNameMap = new Dictionary <Type, List <string> >();
                foreach (PropertyInfo propertyInfo in this._context.GetType().GetInstanceProperties().Where <PropertyInfo>((Func <PropertyInfo, bool>)(p =>
                {
                    if (p.GetIndexParameters().Length == 0)
                    {
                        return(p.DeclaringType != typeof(DbContext));
                    }
                    return(false);
                })))
                {
                    Type setType = DbSetDiscoveryService.GetSetType(propertyInfo.PropertyType);
                    if (setType != (Type)null)
                    {
                        if (!setType.IsValidStructuralType())
                        {
                            throw Error.InvalidEntityType((object)setType);
                        }
                        List <string> stringList;
                        if (!entityTypeToPropertyNameMap.TryGetValue(setType, out stringList))
                        {
                            stringList = new List <string>();
                            entityTypeToPropertyNameMap[setType] = stringList;
                        }
                        stringList.Add(propertyInfo.Name);
                        if (DbSetDiscoveryService.DbSetPropertyShouldBeInitialized(propertyInfo))
                        {
                            MethodInfo method1 = propertyInfo.Setter();
                            if (method1 != (MethodInfo)null && method1.IsPublic)
                            {
                                MethodInfo           method2 = DbSetDiscoveryService.SetMethod.MakeGenericMethod(setType);
                                MethodCallExpression methodCallExpression1 = Expression.Call((Expression)parameterExpression, method2);
                                MethodCallExpression methodCallExpression2 = Expression.Call((Expression)Expression.Convert((Expression)parameterExpression, this._context.GetType()), method1, (Expression)methodCallExpression1);
                                initDelegates.Add(Expression.Lambda <Action <DbContext> >((Expression)methodCallExpression2, parameterExpression).Compile());
                            }
                        }
                    }
                }
                Action <DbContext> setsInitializer = (Action <DbContext>)(dbContext =>
                {
                    foreach (Action <DbContext> action in initDelegates)
                    {
                        action(dbContext);
                    }
                });
                initializersPair = new DbContextTypesInitializersPair(entityTypeToPropertyNameMap, setsInitializer);
                DbSetDiscoveryService._objectSetInitializers.TryAdd(this._context.GetType(), initializersPair);
            }
            return(initializersPair.EntityTypeToPropertyNameMap);
        }
        // <summary>
        // Processes the given context type to determine the DbSet or IDbSet
        // properties and collect root entity types from those properties.  Also, delegates are
        // created to initialize any of these properties that have public setters.
        // If the type has been processed previously in the app domain, then all this information
        // is returned from a cache.
        // </summary>
        // <returns> A dictionary of potential entity type to the list of the names of the properties that used the type. </returns>
        private Dictionary <Type, List <string> > GetSets()
        {
            DbContextTypesInitializersPair setsInfo;

            if (!_objectSetInitializers.TryGetValue(_context.GetType(), out setsInfo))
            {
                // It is possible that multiple threads will enter this code and create the list
                // and the delegates.  However, the result will always be the same so we may, in
                // the rare cases in which this happens, do some work twice, but functionally the
                // outcome will be correct.

                var dbContextParam = Expression.Parameter(typeof(DbContext), "dbContext");
                var initDelegates  = new List <Action <DbContext> >();

                var entityTypes = new Dictionary <Type, List <string> >();

                // Properties declared directly on DbContext such as Database are skipped
                foreach (var propertyInfo in _context.GetType().GetInstanceProperties()
                         .Where(p => p.GetIndexParameters().Length == 0 &&
                                p.DeclaringType != typeof(DbContext)))
                {
                    var entityType = GetSetType(propertyInfo.PropertyType);
                    if (entityType != null)
                    {
                        // We validate immediately because a DbSet/IDbSet must be of
                        // a valid entity type since otherwise you could never use an instance.
                        if (!entityType.IsValidStructuralType())
                        {
                            throw Error.InvalidEntityType(entityType);
                        }

                        List <string> properties;
                        if (!entityTypes.TryGetValue(entityType, out properties))
                        {
                            properties = new List <string>();
                            entityTypes[entityType] = properties;
                        }
                        properties.Add(propertyInfo.Name);

                        if (DbSetPropertyShouldBeInitialized(propertyInfo))
                        {
                            var setter = propertyInfo.Setter();
                            if (setter != null && setter.IsPublic)
                            {
                                var setMethod = SetMethod.MakeGenericMethod(entityType);

                                var newExpression = Expression.Call(dbContextParam, setMethod);
                                var setExpression = Expression.Call(
                                    Expression.Convert(dbContextParam, _context.GetType()), setter, newExpression);
                                initDelegates.Add(
                                    Expression.Lambda <Action <DbContext> >(setExpression, dbContextParam).Compile());
                            }
                        }
                    }
                }

                Action <DbContext> initializer = dbContext =>
                {
                    foreach (var initer in initDelegates)
                    {
                        initer(dbContext);
                    }
                };

                setsInfo = new DbContextTypesInitializersPair(entityTypes, initializer);

                // If TryAdd fails it just means some other thread got here first, which is okay
                // since the end result is the same info anyway.
                _objectSetInitializers.TryAdd(_context.GetType(), setsInfo);
            }
            return(setsInfo.EntityTypeToPropertyNameMap);
        }