Ejemplo n.º 1
0
        // <summary>
        // Processes the given context type to determine the EntityRepository or IRepository
        // 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()
        {
            EntityContextTypesInitializersPair setsInfo;
            var contextType = _context.GetType();

            if (!_objectSetInitializers.TryGetValue(contextType, 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(EntityContext), "dbContext");
                var initDelegates  = new List <Action <EntityContext> >();

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

                var injection = _service.Provider.GetService <IInjectionProvider>();

                // Properties declared directly on DbContext such as Database are skipped
                foreach (var propertyInfo in contextType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                         .Where(p => p.GetIndexParameters().Length == 0 &&
                                p.DeclaringType != typeof(EntityContext)))
                {
                    var entityType = GetSetType(propertyInfo.PropertyType);
                    if (entityType != null)
                    {
                        EntityProxyManager.CompileAll(entityType.Assembly, injection);

                        // 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);
                        }

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

                        properties.Add(propertyInfo.Name);

                        var setter = propertyInfo.GetSetMethod();
                        if (setter != null && setter.IsPublic)
                        {
                            var setMethod = MthSetRep.MakeGenericMethod(entityType);

                            Expression expression = Expression.Call(dbContextParam, setMethod);
                            var        pType      = setter.GetParameters()[0].ParameterType;
                            if (pType != expression.Type)
                            {
                                expression = Expression.Convert(expression, pType);
                            }

                            var setExp = Expression.Call(
                                Expression.Convert(dbContextParam, contextType), setter, expression);

#if !NET35
                            var createExp = Expression.Call(Expression.Constant(_service), MthTryCreateRep, Expression.Constant(entityType));
                            var blockExp  = Expression.Block(setExp, createExp);

                            initDelegates.Add(
                                Expression.Lambda <Action <EntityContext> >(blockExp, dbContextParam).Compile());
#else
                            initDelegates.Add(
                                Expression.Lambda <Action <EntityContext> >(setExp, dbContextParam).Compile());
#endif
                        }
                    }
                }

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

                setsInfo = new EntityContextTypesInitializersPair(typeMap, 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);
        }
Ejemplo n.º 2
0
        // <summary>
        // Processes the given context type to determine the EntityRepository or IRepository
        // 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 EntityContextTypesInitializersPair GetSets()
        {
            var contextType = _context.GetType();

            return(_objectSetInitializers.GetOrAdd(contextType, k =>
            {
                var watch = Stopwatch.StartNew();

                // 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(EntityContext), "dbContext");
                var initDelegates = new List <Action <EntityContext> >();

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

                var reposMaps = (from s in
                                 k.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                 .Where(p => p.GetIndexParameters().Length == 0 &&
                                        p.DeclaringType != typeof(EntityContext))
                                 let entityType = GetSetType(s.PropertyType)
                                                  where entityType != null
                                                  select new EntityRepositoryTypeMapper(s, entityType)).ToList();

                _options.Initializers?.PreInitialize(new EntityContextPreInitializeContext(_context, _contextService, reposMaps));

                // Properties declared directly on DbContext such as Database are skipped
                foreach (var m in reposMaps)
                {
                    // We validate immediately because a DbSet/IDbSet must be of
                    // a valid entity type since otherwise you could never use an instance.
                    if (!m.EntityType.IsValidStructuralType())
                    {
                        //throw Error.InvalidEntityType(entityType);
                    }

                    if (!typeMap.TryGetValue(m.EntityType, out List <string> properties))
                    {
                        properties = new List <string>();
                        typeMap[m.EntityType] = properties;
                    }

                    properties.Add(m.Property.Name);

                    var setter = m.Property.GetSetMethod();
                    if (setter != null && setter.IsPublic)
                    {
                        var setMethod = MethodCache.SetRepository.MakeGenericMethod(m.EntityType);

                        Expression expression = Expression.Call(dbContextParam, setMethod);
                        var pType = setter.GetParameters()[0].ParameterType;
                        if (pType != expression.Type)
                        {
                            expression = Expression.Convert(expression, pType);
                        }

                        var setExp = Expression.Call(
                            Expression.Convert(dbContextParam, contextType), setter, expression);

                        initDelegates.Add(
                            Expression.Lambda <Action <EntityContext> >(setExp, dbContextParam).Compile());
                    }
                }

                void initializer(EntityContext dbContext)
                {
                    foreach (var initer in initDelegates)
                    {
                        initer(dbContext);
                    }
                }

                Tracer.Debug($"The repositories of {contextType.Name} was initialized ({watch.ElapsedMilliseconds}ms).");

                return new EntityContextTypesInitializersPair(typeMap, initializer);
            }));
        }