/// <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>
        protected override IClrPropertySetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            PropertyInfo propertyInfo, IPropertyBase propertyBase)
        {
            var memberInfo = propertyBase?.GetMemberInfo(forConstruction: false, forSet: true)
                             ?? propertyInfo.FindGetterProperty();

            if (memberInfo == null)
            {
                throw new InvalidOperationException(
                          CoreStrings.NoSetter(propertyInfo.Name, propertyInfo.DeclaringType.ShortDisplayName(), nameof(PropertyAccessMode)));
            }

            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
            var valueParameter  = Expression.Parameter(typeof(TValue), "value");

            var setter = Expression.Lambda <Action <TEntity, TValue> >(
                Expression.Assign(
                    Expression.MakeMemberAccess(entityParameter, memberInfo),
                    valueParameter),
                entityParameter,
                valueParameter).Compile();

            var propertyType = propertyBase?.ClrType ?? propertyInfo?.PropertyType;

            return(propertyType.IsNullableType() &&
                   propertyType.UnwrapNullableType().GetTypeInfo().IsEnum
                ? new NullableEnumClrPropertySetter <TEntity, TValue, TNonNullableEnumValue>(setter)
                : (IClrPropertySetter) new ClrPropertySetter <TEntity, TValue>(setter));
        }
        /// <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>
        protected override IClrPropertySetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            PropertyInfo propertyInfo, IPropertyBase propertyBase)
        {
            var memberInfo = propertyBase?.GetMemberInfo(forConstruction: false, forSet: true)
                             ?? propertyInfo.FindGetterProperty();

            if (memberInfo == null)
            {
                throw new InvalidOperationException(
                          CoreStrings.NoSetter(propertyInfo.Name, propertyInfo.DeclaringType.ShortDisplayName(), nameof(PropertyAccessMode)));
            }

            var entityParameter    = Expression.Parameter(typeof(TEntity), "entity");
            var valueParameter     = Expression.Parameter(typeof(TValue), "value");
            var memberType         = memberInfo.GetMemberType();
            var convertedParameter = memberType == typeof(TValue)
                ? (Expression)valueParameter
                : Expression.Convert(valueParameter, memberType);

            Expression writeExpression;

            if (memberInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(typeof(TEntity).GetTypeInfo()))
            {
                writeExpression = Expression.MakeMemberAccess(entityParameter, memberInfo)
                                  .Assign(convertedParameter);
            }
            else
            {
                // This path handles properties that exist only on proxy types and so only exist if the instance is a proxy
                var converted = Expression.Variable(memberInfo.DeclaringType, "converted");

                writeExpression = Expression.Block(
                    new[]
                {
                    converted
                },
                    new List <Expression>
                {
                    Expression.Assign(
                        converted,
                        Expression.TypeAs(entityParameter, memberInfo.DeclaringType)),
                    Expression.IfThen(
                        Expression.ReferenceNotEqual(converted, Expression.Constant(null)),
                        Expression.MakeMemberAccess(converted, memberInfo)
                        .Assign(convertedParameter))
                });
            }

            var setter = Expression.Lambda <Action <TEntity, TValue> >(
                writeExpression,
                entityParameter,
                valueParameter).Compile();

            var propertyType = propertyBase?.ClrType ?? propertyInfo?.PropertyType;

            return(propertyType.IsNullableType() &&
                   propertyType.UnwrapNullableType().GetTypeInfo().IsEnum
                ? new NullableEnumClrPropertySetter <TEntity, TValue, TNonNullableEnumValue>(setter)
                : (IClrPropertySetter) new ClrPropertySetter <TEntity, TValue>(setter));
        }
Пример #3
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>
        protected override IClrPropertyGetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            PropertyInfo propertyInfo, IPropertyBase propertyBase)
        {
            var memberInfo = propertyBase?.GetMemberInfo(forConstruction: false, forSet: false)
                             ?? propertyInfo.FindGetterProperty();

            if (memberInfo == null)
            {
                throw new InvalidOperationException(
                          CoreStrings.NoGetter(propertyInfo.Name, propertyInfo.DeclaringType.ShortDisplayName(), nameof(PropertyAccessMode)));
            }

            var entityParameter   = Expression.Parameter(typeof(TEntity), "entity");
            var memberType        = memberInfo.GetMemberType();
            var defaultExpression = Expression.Default(memberType);

            Expression readExpression;

            if (memberInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(typeof(TEntity).GetTypeInfo()))
            {
                readExpression = Expression.MakeMemberAccess(entityParameter, memberInfo);
            }
            else
            {
                // This path handles properties that exist only on proxy types and so only exist if the instance is a proxy
                var converted = Expression.Variable(memberInfo.DeclaringType, "converted");

                readExpression = Expression.Block(
                    new[] { converted },
                    new List <Expression>
                {
                    Expression.Assign(
                        converted,
                        Expression.TypeAs(entityParameter, memberInfo.DeclaringType)),
                    Expression.Condition(
                        Expression.ReferenceEqual(converted, Expression.Constant(null)),
                        defaultExpression,
                        Expression.MakeMemberAccess(converted, memberInfo))
                });
            }

            var property = propertyBase as IProperty;
            var comparer = memberType.IsNullableType()
                ? null
                : property?.GetValueComparer()
                           ?? property?.FindMapping()?.Comparer
                           ?? (ValueComparer)Activator.CreateInstance(
                typeof(ValueComparer <>).MakeGenericType(memberType),
                new object[] { false });

            var hasDefaultValueExpression = comparer == null
                ? Expression.Equal(readExpression, defaultExpression)
                : comparer.ExtractEqualsBody(readExpression, defaultExpression);

            return(new ClrPropertyGetter <TEntity, TValue>(
                       Expression.Lambda <Func <TEntity, TValue> >(readExpression, entityParameter).Compile(),
                       Expression.Lambda <Func <TEntity, bool> >(hasDefaultValueExpression, entityParameter).Compile()));
        }
        private static Func <InternalEntityEntry, TProperty> CreateCurrentValueGetter <TProperty>(
            IPropertyBase propertyBase, bool useStoreGeneratedValues)
        {
            var entityClrType  = propertyBase.DeclaringType.ClrType;
            var entryParameter = Expression.Parameter(typeof(InternalEntityEntry), "entry");

            var        shadowIndex = propertyBase.GetShadowIndex();
            Expression currentValueExpression;

            if (shadowIndex >= 0)
            {
                currentValueExpression = Expression.Call(
                    entryParameter,
                    InternalEntityEntry.ReadShadowValueMethod.MakeGenericMethod(typeof(TProperty)),
                    Expression.Constant(shadowIndex));
            }
            else
            {
                var convertedExpression = Expression.Convert(
                    Expression.Property(entryParameter, "Entity"),
                    entityClrType);

                currentValueExpression = Expression.MakeMemberAccess(
                    convertedExpression,
                    propertyBase.GetMemberInfo(forConstruction: false, forSet: false));

                if (currentValueExpression.Type != typeof(TProperty))
                {
                    currentValueExpression = Expression.Convert(currentValueExpression, typeof(TProperty));
                }
            }

            var storeGeneratedIndex = propertyBase.GetStoreGeneratedIndex();

            if (useStoreGeneratedValues &&
                storeGeneratedIndex >= 0)
            {
                currentValueExpression = Expression.Call(
                    entryParameter,
                    InternalEntityEntry.ReadStoreGeneratedValueMethod.MakeGenericMethod(typeof(TProperty)),
                    currentValueExpression,
                    Expression.Constant(storeGeneratedIndex));
            }

            return(Expression.Lambda <Func <InternalEntityEntry, TProperty> >(
                       currentValueExpression,
                       entryParameter)
                   .Compile());
        }
Пример #5
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>
        protected override IClrPropertyGetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            PropertyInfo propertyInfo, IPropertyBase propertyBase)
        {
            var memberInfo = propertyBase?.GetMemberInfo(forConstruction: false, forSet: false)
                             ?? propertyInfo.FindGetterProperty();

            if (memberInfo == null)
            {
                throw new InvalidOperationException(
                          CoreStrings.NoGetter(propertyInfo.Name, propertyInfo.DeclaringType.ShortDisplayName(), nameof(PropertyAccessMode)));
            }

            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");

            return(new ClrPropertyGetter <TEntity, TValue>(Expression.Lambda <Func <TEntity, TValue> >(
                                                               Expression.MakeMemberAccess(entityParameter, memberInfo),
                                                               entityParameter).Compile()));
        }
Пример #6
0
 /// <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 override IClrPropertySetter Create(IPropertyBase property)
 => property as IClrPropertySetter ?? Create(property.GetMemberInfo(forMaterialization: false, forSet: true), property);
        private static Func <IUpdateEntry, TProperty> CreateCurrentValueGetter <TProperty>(
            IPropertyBase propertyBase,
            bool useStoreGeneratedValues)
        {
            var entityClrType   = propertyBase.DeclaringType.ClrType;
            var updateParameter = Expression.Parameter(typeof(IUpdateEntry), "entry");
            var entryParameter  = Expression.Convert(updateParameter, typeof(InternalEntityEntry));

            var        shadowIndex = propertyBase.GetShadowIndex();
            Expression currentValueExpression;

            if (shadowIndex >= 0)
            {
                currentValueExpression = Expression.Call(
                    entryParameter,
                    InternalEntityEntry.ReadShadowValueMethod.MakeGenericMethod(typeof(TProperty)),
                    Expression.Constant(shadowIndex));
            }
            else
            {
                var convertedExpression = Expression.Convert(
                    Expression.Property(entryParameter, "Entity"),
                    entityClrType);

                var memberInfo = propertyBase.GetMemberInfo(forMaterialization: false, forSet: false);
                currentValueExpression = PropertyBase.CreateMemberAccess(propertyBase, convertedExpression, memberInfo);

                if (currentValueExpression.Type != typeof(TProperty))
                {
                    currentValueExpression = Expression.Condition(
                        currentValueExpression.MakeHasDefaultValue(propertyBase),
                        Expression.Constant(default(TProperty), typeof(TProperty)),
                        Expression.Convert(currentValueExpression, typeof(TProperty)));
                }
            }

            var storeGeneratedIndex = propertyBase.GetStoreGeneratedIndex();

            if (storeGeneratedIndex >= 0)
            {
                if (useStoreGeneratedValues)
                {
                    currentValueExpression = Expression.Condition(
                        Expression.Equal(
                            currentValueExpression,
                            Expression.Constant(default(TProperty), typeof(TProperty))),
                        Expression.Call(
                            entryParameter,
                            InternalEntityEntry.ReadStoreGeneratedValueMethod.MakeGenericMethod(typeof(TProperty)),
                            Expression.Constant(storeGeneratedIndex)),
                        currentValueExpression);
                }

                currentValueExpression = Expression.Condition(
                    Expression.Equal(
                        currentValueExpression,
                        Expression.Constant(default(TProperty), typeof(TProperty))),
                    Expression.Call(
                        entryParameter,
                        InternalEntityEntry.ReadTemporaryValueMethod.MakeGenericMethod(typeof(TProperty)),
                        Expression.Constant(storeGeneratedIndex)),
                    currentValueExpression);
            }

            return(Expression.Lambda <Func <IUpdateEntry, TProperty> >(
                       currentValueExpression,
                       updateParameter)
                   .Compile());
        }
        private void MemberInfoTestCommon(
            IPropertyBase propertyBase, PropertyAccessMode?accessMode, string forConstruction, string forSet, string forGet)
        {
            string failMessage = null;

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: true, forSet: true);
                Assert.Equal(forConstruction, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.SetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forConstruction, ex.Message);
                failMessage = ex.Message;
            }

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: false, forSet: true);
                Assert.Equal(forSet, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.SetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forSet, ex.Message);
                failMessage = failMessage ?? ex.Message;
            }

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: false, forSet: false);
                Assert.Equal(forGet, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.GetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forGet, ex.Message);
                failMessage = failMessage ?? ex.Message;
            }

            try
            {
                InMemoryTestHelpers.Instance.CreateContextServices().GetRequiredService <IModelValidator>()
                .Validate(propertyBase.DeclaringType.Model);

                Assert.Null(failMessage);
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(failMessage, ex.Message);
            }
        }
Пример #9
0
        public void MemberInfoTestCommon(
            IPropertyBase propertyBase, PropertyAccessMode?accessMode, string forConstruction, string forSet, string forGet)
        {
            string failMessage = null;

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: true, forSet: true);
                Assert.Equal(forConstruction, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.SetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forConstruction, ex.Message);
                failMessage = ex.Message;
            }

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: false, forSet: true);
                Assert.Equal(forSet, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.SetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forSet, ex.Message);
                failMessage = failMessage ?? ex.Message;
            }

            try
            {
                var memberInfo = propertyBase.GetMemberInfo(forConstruction: false, forSet: false);
                Assert.Equal(forGet, memberInfo?.Name);

                var propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    Assert.NotNull(propertyInfo.GetMethod);
                }
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(forGet, ex.Message);
                failMessage = failMessage ?? ex.Message;
            }

            try
            {
                new TestModelValidator().Validate(propertyBase.DeclaringType.Model);
                Assert.Null(failMessage);
            }
            catch (InvalidOperationException ex)
            {
                Assert.Equal(failMessage, ex.Message);
            }
        }
Пример #10
0
        private static Func <InternalEntityEntry, TProperty> CreateCurrentValueGetter <TProperty>(
            IPropertyBase propertyBase, bool useStoreGeneratedValues)
        {
            var entityClrType  = propertyBase.DeclaringType.ClrType;
            var entryParameter = Expression.Parameter(typeof(InternalEntityEntry), "entry");

            var        shadowIndex = propertyBase.GetShadowIndex();
            Expression currentValueExpression;

            if (shadowIndex >= 0)
            {
                currentValueExpression = Expression.Call(
                    entryParameter,
                    InternalEntityEntry.ReadShadowValueMethod.MakeGenericMethod(typeof(TProperty)),
                    Expression.Constant(shadowIndex));
            }
            else
            {
                var convertedExpression = Expression.Convert(
                    Expression.Property(entryParameter, "Entity"),
                    entityClrType);

                currentValueExpression = CreateMemberAccess(
                    convertedExpression,
                    propertyBase.GetMemberInfo(forMaterialization: false, forSet: false));

                if (currentValueExpression.Type != typeof(TProperty))
                {
                    currentValueExpression = Expression.Convert(currentValueExpression, typeof(TProperty));
                }
            }

            var storeGeneratedIndex = propertyBase.GetStoreGeneratedIndex();

            if (storeGeneratedIndex >= 0)
            {
                if (useStoreGeneratedValues)
                {
                    currentValueExpression = Expression.Condition(
                        Expression.Equal(
                            currentValueExpression,
                            Expression.Constant(default(TProperty), typeof(TProperty))),
                        Expression.Call(
                            entryParameter,
                            InternalEntityEntry.ReadStoreGeneratedValueMethod.MakeGenericMethod(typeof(TProperty)),
                            Expression.Constant(storeGeneratedIndex)),
                        currentValueExpression);
                }

                currentValueExpression = Expression.Condition(
                    Expression.Equal(
                        currentValueExpression,
                        Expression.Constant(default(TProperty), typeof(TProperty))),
                    Expression.Call(
                        entryParameter,
                        InternalEntityEntry.ReadTemporaryValueMethod.MakeGenericMethod(typeof(TProperty)),
                        Expression.Constant(storeGeneratedIndex)),
                    currentValueExpression);
            }

            return(Expression.Lambda <Func <InternalEntityEntry, TProperty> >(
                       currentValueExpression,
                       entryParameter)
                   .Compile());

            Expression CreateMemberAccess(Expression parameter, MemberInfo memberInfo)
            {
                return(propertyBase?.IsIndexerProperty() == true
                    ? Expression.MakeIndex(
                           parameter, (PropertyInfo)memberInfo, new List <Expression>() { Expression.Constant(propertyBase.Name) })
                    : (Expression)Expression.MakeMemberAccess(parameter, memberInfo));
            }
        }