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