static Expression CreateMemberAssignment(Expression parameter, MemberInfo memberInfo, IPropertyBase property, Expression value)
 => property.IsIndexerProperty()
         ? Expression.Assign(
     Expression.MakeIndex(
         parameter, (PropertyInfo)memberInfo, new List <Expression> {
     Expression.Constant(property.Name)
 }),
     value)
         : Expression.MakeMemberAccess(parameter, memberInfo).Assign(value);
        /// <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 IClrPropertyGetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            MemberInfo memberInfo, IPropertyBase propertyBase)
        {
            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");

            Expression readExpression;

            if (memberInfo.DeclaringType.IsAssignableFrom(typeof(TEntity)))
            {
                readExpression = CreateMemberAccess(entityParameter);
            }
            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)),
                        Expression.Default(memberInfo.GetMemberType()),
                        CreateMemberAccess(converted))
                });
            }

            var hasDefaultValueExpression = readExpression.MakeHasDefaultValue <TValue>(propertyBase);

            if (readExpression.Type != typeof(TValue))
            {
                readExpression = Expression.Condition(
                    hasDefaultValueExpression,
                    Expression.Constant(default(TValue), typeof(TValue)),
                    Expression.Convert(readExpression, typeof(TValue)));
            }

            return(new ClrPropertyGetter <TEntity, TValue>(
                       Expression.Lambda <Func <TEntity, TValue> >(readExpression, entityParameter).Compile(),
                       Expression.Lambda <Func <TEntity, bool> >(hasDefaultValueExpression, entityParameter).Compile()));

            Expression CreateMemberAccess(Expression parameter)
            {
                return(propertyBase?.IsIndexerProperty() == true
                    ? Expression.MakeIndex(
                           parameter, (PropertyInfo)memberInfo, new List <Expression>() { Expression.Constant(propertyBase.Name) })
                    : (Expression)Expression.MakeMemberAccess(parameter, memberInfo));
            }
        }
Пример #3
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));
            }
        }
Пример #4
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>
        protected override IClrPropertyGetter CreateGeneric <TEntity, TValue, TNonNullableEnumValue>(
            MemberInfo memberInfo, IPropertyBase propertyBase)
        {
            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");

            Expression readExpression;

            if (memberInfo.DeclaringType.IsAssignableFrom(typeof(TEntity)))
            {
                readExpression = CreateMemberAccess(entityParameter);
            }
            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)),
                        Expression.Default(memberInfo.GetMemberType()),
                        CreateMemberAccess(converted))
                });
            }

            if (readExpression.Type != typeof(TValue))
            {
                readExpression = Expression.Convert(readExpression, typeof(TValue));
            }

            Expression hasDefaultValueExpression;

            if (!readExpression.Type.IsValueType)
            {
                hasDefaultValueExpression
                    = Expression.ReferenceEqual(
                          readExpression,
                          Expression.Constant(null, readExpression.Type));
            }
            else if (readExpression.Type.IsGenericType &&
                     readExpression.Type.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                hasDefaultValueExpression
                    = Expression.Not(
                          Expression.Call(
                              readExpression,
                              readExpression.Type.GetMethod("get_HasValue")));
            }
            else
            {
                var property = propertyBase as IProperty;
                var comparer = property?.GetValueComparer()
                               ?? property?.FindTypeMapping()?.Comparer
                               ?? ValueComparer.CreateDefault(typeof(TValue), favorStructuralComparisons: false);

                hasDefaultValueExpression = comparer.ExtractEqualsBody(
                    comparer.Type != typeof(TValue)
                        ? Expression.Convert(readExpression, comparer.Type)
                        : readExpression,
                    Expression.Default(comparer.Type));
            }

            return(new ClrPropertyGetter <TEntity, TValue>(
                       Expression.Lambda <Func <TEntity, TValue> >(readExpression, entityParameter).Compile(),
                       Expression.Lambda <Func <TEntity, bool> >(hasDefaultValueExpression, entityParameter).Compile()));

            Expression CreateMemberAccess(Expression parameter)
            {
                return(propertyBase?.IsIndexerProperty() == true
                    ? Expression.MakeIndex(
                           entityParameter, (PropertyInfo)memberInfo, new List <Expression>() { Expression.Constant(propertyBase.Name) })
                    : (Expression)Expression.MakeMemberAccess(parameter, memberInfo));
            }
        }
Пример #5
0
    private IClrCollectionAccessor?Create(IPropertyBase navigation, IEntityType?targetType)
    {
        // ReSharper disable once SuspiciousTypeConversion.Global
        if (navigation is IClrCollectionAccessor accessor)
        {
            return(accessor);
        }

        if (targetType == null)
        {
            return(null);
        }

        var memberInfo   = GetMostDerivedMemberInfo();
        var propertyType = navigation.IsIndexerProperty() ? navigation.ClrType : memberInfo.GetMemberType();
        var elementType  = propertyType.TryGetElementType(typeof(IEnumerable <>));

        if (elementType == null)
        {
            throw new InvalidOperationException(
                      CoreStrings.NavigationBadType(
                          navigation.Name,
                          navigation.DeclaringType.DisplayName(),
                          propertyType.ShortDisplayName(),
                          targetType.DisplayName()));
        }

        if (propertyType.IsArray)
        {
            throw new InvalidOperationException(
                      CoreStrings.NavigationArray(
                          navigation.Name,
                          navigation.DeclaringType.DisplayName(),
                          propertyType.ShortDisplayName()));
        }

        var boundMethod = _genericCreate.MakeGenericMethod(
            memberInfo.DeclaringType !, propertyType, elementType);

        try
        {
            return((IClrCollectionAccessor?)boundMethod.Invoke(
                       null, new object[] { navigation }));
        }
        catch (TargetInvocationException invocationException)
        {
            throw invocationException.InnerException !;
        }

        MemberInfo GetMostDerivedMemberInfo()
        {
            var propertyInfo = navigation.PropertyInfo !;
            var fieldInfo    = navigation.FieldInfo !;

            return(fieldInfo == null
                ? propertyInfo
                : propertyInfo == null
                    ? fieldInfo
                    : fieldInfo.FieldType.IsAssignableFrom(propertyInfo.PropertyType)
                        ? propertyInfo
                        : fieldInfo);
        }
    }