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