Beispiel #1
0
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual bool TryBindConstructor(
            IMutableEntityType entityType,
            ConstructorInfo constructor,
            out ConstructorBinding binding,
            out IEnumerable <ParameterInfo> failedBindings)
        {
            IEnumerable <(ParameterInfo Parameter, ParameterBinding Binding)> bindings
                = constructor.GetParameters().Select(
                      p => (p, _factories.Select(f => f.TryBindParameter(entityType, p))
                            .FirstOrDefault(b => b != null)))
                  .ToList();

            if (bindings.Any(b => b.Binding == null))
            {
                failedBindings = bindings.Where(b => b.Binding == null).Select(b => b.Parameter);
                binding        = null;

                return(false);
            }

            failedBindings = null;
            binding        = new DirectConstructorBinding(constructor, bindings.Select(b => b.Binding).ToList());

            return(true);
        }
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual bool TryBindConstructor(
            IConventionEntityType entityType,
            ConstructorInfo constructor,
            out ConstructorBinding binding,
            out IEnumerable <ParameterInfo> failedBindings)
        {
            IEnumerable <(ParameterInfo Parameter, ParameterBinding Binding)> bindings
                = constructor.GetParameters().Select(
                      p => (p, _propertyFactory.TryBindParameter(entityType, p.ParameterType, p.Name)
                            ?? _factories.FindFactory(p.ParameterType, p.Name)?.Bind(entityType, p.ParameterType, p.Name)))
                  .ToList();

            if (bindings.Any(b => b.Binding == null))
            {
                failedBindings = bindings.Where(b => b.Binding == null).Select(b => b.Parameter);
                binding        = null;

                return(false);
            }

            failedBindings = null;
            binding        = new DirectConstructorBinding(constructor, bindings.Select(b => b.Binding).ToList());

            return(true);
        }
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual Expression CreateMaterializeExpression(
            IEntityType entityType,
            string entityInstanceName,
            Expression materializationExpression,
            int[] indexMap = null)
        {
            if (!entityType.HasClrType())
            {
                throw new InvalidOperationException(CoreStrings.NoClrType(entityType.DisplayName()));
            }

            if (entityType.IsAbstract())
            {
                throw new InvalidOperationException(CoreStrings.CannotMaterializeAbstractType(entityType));
            }

            var constructorBinding = (ConstructorBinding)entityType[CoreAnnotationNames.ConstructorBinding];

            if (constructorBinding == null)
            {
                var constructorInfo = entityType.ClrType.GetDeclaredConstructor(null);

                if (constructorInfo == null)
                {
                    throw new InvalidOperationException(CoreStrings.NoParameterlessConstructor(entityType.DisplayName()));
                }

                constructorBinding = new DirectConstructorBinding(constructorInfo, Array.Empty <ParameterBinding>());
            }

            // This is to avoid breaks because this method used to expect ValueBuffer but now expects MaterializationContext
            var valueBufferExpression = materializationExpression;

            if (valueBufferExpression.Type == typeof(MaterializationContext))
            {
                valueBufferExpression = Expression.Call(materializationExpression, MaterializationContext.GetValueBufferMethod);
            }
            else
            {
                materializationExpression = Expression.New(MaterializationContext.ObsoleteConstructor, materializationExpression);
            }

            var bindingInfo = new ParameterBindingInfo(
                entityType,
                materializationExpression,
                indexMap);

            var properties = new HashSet <IPropertyBase>(
                entityType.GetServiceProperties().Cast <IPropertyBase>()
                .Concat(
                    entityType
                    .GetProperties()
                    .Where(p => !p.IsShadowProperty())));

            foreach (var consumedProperty in constructorBinding
                     .ParameterBindings
                     .SelectMany(p => p.ConsumedProperties))
            {
                properties.Remove(consumedProperty);
            }

            var constructorExpression = constructorBinding.CreateConstructorExpression(bindingInfo);

            if (properties.Count == 0)
            {
                return(constructorExpression);
            }

            var instanceVariable = Expression.Variable(constructorBinding.RuntimeType, entityInstanceName);

            var blockExpressions
                = new List <Expression>
                {
                Expression.Assign(
                    instanceVariable,
                    constructorExpression)
                };

            var indexerPropertyInfo = entityType.FindIndexerProperty();

            foreach (var property in properties)
            {
                var memberInfo = property.GetMemberInfo(forConstruction: true, forSet: true);

                var readValueExpression
                    = property is IServiceProperty serviceProperty
                        ? serviceProperty.GetParameterBinding().BindToParameter(bindingInfo)
                        : CreateReadValueExpression(
                          valueBufferExpression,
                          memberInfo.GetMemberType(),
                          indexMap?[property.GetIndex()] ?? property.GetIndex(),
                          property);

                blockExpressions.Add(
                    property.IsIndexedProperty()
                        ? Expression.Assign(
                        Expression.MakeIndex(
                            instanceVariable,
                            indexerPropertyInfo,
                            new[]
                {
                    Expression.Constant(property.Name)
                }),
                        readValueExpression)
                        : Expression.MakeMemberAccess(
                        instanceVariable,
                        memberInfo).Assign(
                        readValueExpression));
            }

            blockExpressions.Add(instanceVariable);

            return(Expression.Block(
                       new[]
            {
                instanceVariable
            }, blockExpressions));
        }