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