public static void ApplyGlobalFilters <TInterface>(this ModelBuilder modelBuilder, Expression <Func <TInterface, bool> > expression) { var entities = modelBuilder.Model .GetEntityTypes() .Where(e => e.ClrType.GetInterface(typeof(TInterface).Name) != null) .Select(e => e.ClrType); foreach (var entity in entities) { var newParam = Expression.Parameter(entity); var newbody = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), newParam, expression.Body); modelBuilder.Entity(entity).HasQueryFilter(Expression.Lambda(newbody, newParam)); } }
/// <summary> /// Apply global filters to all types inherited from T. /// </summary> /// <typeparam name="T">Base type for entries.</typeparam> /// <param name="modelBuilder">Model builder.</param> /// <param name="expression">Expression to filter.</param> public static void ApplyGlobalFilters <T>(this ModelBuilder modelBuilder, Expression <Func <T, bool> > expression) { IEnumerable <Type>?entities = modelBuilder.Model .GetEntityTypes() .Where(e => typeof(T).IsAssignableFrom(e.ClrType)) .Select(e => e.ClrType); foreach (Type?entity in entities) { ParameterExpression?newParam = Expression.Parameter(entity); Expression? newbody = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), newParam, expression.Body); modelBuilder.Entity(entity).HasQueryFilter(Expression.Lambda(newbody, newParam)); } }
protected override ShapedQueryExpression TranslateSum(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { var selectExpression = (SelectExpression)source.QueryExpression; selectExpression.PrepareForAggregate(); var newSelector = selector == null || selector.Body == selector.Parameters[0] ? selectExpression.GetMappedProjection(new ProjectionMember()) : ReplacingExpressionVisitor.Replace(selector.Parameters.Single(), source.ShaperExpression, selector.Body); var projection = _sqlTranslator.TranslateSum(newSelector); return(AggregateResultShaper(source, projection, throwOnNullResult: false, resultType)); }
protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) { if (selector.Body == selector.Parameters[0]) { return(source); } var newSelectorBody = ReplacingExpressionVisitor.Replace(selector.Parameters.Single(), source.ShaperExpression, selector.Body); source.ShaperExpression = _projectionBindingExpressionVisitor .Translate((SelectExpression)source.QueryExpression, newSelectorBody); return(source); }
public static void ApplyGlobalFilters <TInterface>(this ModelBuilder modelBuilder, Expression <Func <TInterface, bool> > expression) { foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { if (entityType.ClrType.GetInterface(typeof(TInterface).Name) != null) { var newParams = Expression.Parameter(entityType.ClrType); var newBody = ReplacingExpressionVisitor.Replace( expression.Parameters.Single(), newParams, expression.Body); modelBuilder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(newBody, newParams)); } } }
protected Expression ExpandNavigation( Expression root, EntityReference entityReference, INavigation navigation, bool derivedTypeConversion) { if (entityReference.NavigationMap.TryGetValue(navigation, out var expansion)) { return(expansion); } if (navigation.ForeignKey.IsOwnership) { var ownedEntityReference = new EntityReference(navigation.GetTargetType()); ownedEntityReference.MarkAsOptional(); ownedEntityReference.SetIncludePaths(entityReference.IncludePaths[navigation]); var ownedExpansion = new OwnedNavigationReference(root, navigation, ownedEntityReference); entityReference.NavigationMap[navigation] = ownedExpansion; return(ownedExpansion); } var innerQueryableType = navigation.GetTargetType().ClrType; var innerQueryable = NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(innerQueryableType); var innerSource = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable); if (entityReference.IncludePaths.ContainsKey(navigation)) { var innerIncludeTreeNode = entityReference.IncludePaths[navigation]; var innerEntityReference = (EntityReference)((NavigationTreeExpression)innerSource.PendingSelector).Value; innerEntityReference.SetIncludePaths(innerIncludeTreeNode); } var innerParameter = Expression.Parameter(innerSource.SourceElementType, "i"); Expression outerKey; if (root is NavigationExpansionExpression innerNavigationExpansionExpression && innerNavigationExpansionExpression.CardinalityReducingGenericMethodInfo != null) { // This is FirstOrDefault ending so we need to push down properties. var temporaryParameter = Expression.Parameter(root.Type); var temporaryKey = CreateKeyAccessExpression(temporaryParameter, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties : navigation.ForeignKey.PrincipalKey.Properties); var newSelector = ReplacingExpressionVisitor.Replace( temporaryParameter, innerNavigationExpansionExpression.PendingSelector, temporaryKey); innerNavigationExpansionExpression.ApplySelector(newSelector); outerKey = innerNavigationExpansionExpression; }
// This is an expansion on the limitation in EFCore as described in ConvertFilterExpression<T>. // Since EFCore currently only allows 1 HasQueryFilter() call (and ignores all previous calls), // we need to create a single lambda expression for all filters. // See: https://github.com/aspnet/EntityFrameworkCore/issues/10275 /// <summary> /// Combines the query filters. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="andAlsoExpressions">The and also expressions.</param> /// <returns>LambdaExpression.</returns> private static LambdaExpression CombineQueryFilters(Type entityType, IEnumerable <LambdaExpression> andAlsoExpressions) { var newParam = Expression.Parameter(entityType); var andAlsoExprBase = (Expression <Func <BaseTenantEntity, bool> >)(_ => true); var andAlsoExpr = ReplacingExpressionVisitor.Replace(andAlsoExprBase.Parameters.Single(), newParam, andAlsoExprBase.Body); foreach (var expressionBase in andAlsoExpressions.EnsureNotNull()) { var expression = ReplacingExpressionVisitor.Replace(expressionBase.Parameters.Single(), newParam, expressionBase.Body); andAlsoExpr = Expression.AndAlso(andAlsoExpr, expression); } return(Expression.Lambda(andAlsoExpr, newParam)); }
public static LinqBatchItem <TResult> Create <T, TResult>(IQueryable <T> query, Expression <Func <IQueryable <T>, TResult> > selector) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (selector == null) { throw new ArgumentNullException(nameof(selector)); } var expression = ReplacingExpressionVisitor .Replace(selector.Parameters.Single(), query.Expression, selector.Body); return(GetForQuery <TResult>(query, expression)); }
/// <summary> /// Takes <see cref="EqualsExpression" /> and replaces the two parameters with the given expressions, /// returning the transformed body. /// </summary> /// <param name="leftExpression"> The new left expression. </param> /// <param name="rightExpression"> The new right expression. </param> /// <returns> The body of the lambda with left and right parameters replaced.</returns> public virtual Expression ExtractEqualsBody( [NotNull] Expression leftExpression, [NotNull] Expression rightExpression) { Check.NotNull(leftExpression, nameof(leftExpression)); Check.NotNull(rightExpression, nameof(rightExpression)); return(ReplacingExpressionVisitor.Replace( EqualsExpression.Parameters[1], rightExpression, ReplacingExpressionVisitor.Replace( EqualsExpression.Parameters[0], leftExpression, EqualsExpression.Body))); }
protected override Expression VisitConstant(ConstantExpression constantExpression) { if (_store != null && constantExpression.IsEntityQueryable()) { var type = ((IQueryable)constantExpression.Value).ElementType; var entityType = _queryCompilationContext.Model.FindEntityType(type)?.RootType(); if (entityType != null && _store.Dictionary.TryGetValue(type, out var lambda)) { Expression newExpression = constantExpression; var parameterizedFilter = (LambdaExpression)_queryModelGenerator .ExtractParameters( _queryCompilationContext.Logger, lambda, new Parameters(this.ContextParameters), parameterize: false, generateContextAccessors: true); var oldParameterExpression = parameterizedFilter.Parameters[0]; var newParameterExpression = Expression.Parameter(type, oldParameterExpression.Name); var predicateExpression = ReplacingExpressionVisitor .Replace( oldParameterExpression, newParameterExpression, parameterizedFilter.Body); var whereExpression = Expression.Call( _whereMethod.MakeGenericMethod(type), newExpression, Expression.Lambda( predicateExpression, newParameterExpression)); var subQueryModel = _queryModelGenerator.ParseQuery(whereExpression); newExpression = new SubQueryExpression(subQueryModel); return(newExpression); } } return(base.VisitConstant(constantExpression)); }
/// <summary> /// Wraps the query in a deferred <see cref="IFutureValue{T}"/> which will trigger a batch of all pending future queries /// when its <see cref="IFutureValue{T}.Value"/> is read. /// </summary> /// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param> /// <param name="selector">An aggregation function to apply to <paramref name="source"/>.</param> /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> /// <typeparam name="TResult">The type of the value returned by the function represented by <paramref name="selector"/>.</typeparam> /// <returns>A <see cref="IFutureValue{T}"/>.</returns> /// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception> /// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception> public static IFutureValue <TResult> ToFutureValue <TSource, TResult>(this IQueryable <TSource> source, Expression <Func <IQueryable <TSource>, TResult> > selector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (!(source.Provider is INhQueryProvider provider)) { throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}"); } var expression = ReplacingExpressionVisitor .Replace(selector.Parameters.Single(), source.Expression, selector.Body); return(provider.ExecuteFutureValue <TResult>(expression)); }
/// <summary> /// Agrega un filtro global. /// </summary> /// <typeparam name="TInterface">Tipo de interface.</typeparam> /// <param name="modelBuilder">Modelo de entidades.</param> /// <param name="expression">Expresión a validar.</param> public static void WithFilter <TInterface>(this ModelBuilder modelBuilder, Expression <Func <TInterface, bool> > expression) { var entities = modelBuilder.GetEntityTypes <TInterface>(); if (entities is not null) { foreach (var entity in entities) { var newParam = Expression.Parameter(entity); var newbody = ReplacingExpressionVisitor.Replace(expression?.Parameters.Single(), newParam, expression?.Body); modelBuilder?.Entity(entity).HasQueryFilter(Expression.Lambda(newbody, newParam)); } } }
/// <summary> /// Replaces the given parameter with a back-reference to the <see cref="IQuerySource" /> corresponding to /// <paramref name="referencedNode" />. /// </summary> /// <param name="referencedNode">The referenced node.</param> /// <param name="parameterToReplace">The parameter to replace with a <see cref="QuerySourceReferenceExpression" />.</param> /// <param name="expression">The expression in which to replace the parameter.</param> /// <param name="context">The clause generation context.</param> /// <returns> /// <paramref name="expression" />, with <paramref name="parameterToReplace" /> replaced with a /// <see cref="QuerySourceReferenceExpression" /> /// pointing to the clause corresponding to <paramref name="referencedNode" />. /// </returns> public static Expression ReplaceParameterWithReference( IQuerySourceExpressionNode referencedNode, ParameterExpression parameterToReplace, Expression expression, ClauseGenerationContext context) { ArgumentUtility.CheckNotNull("referencedNode", referencedNode); ArgumentUtility.CheckNotNull("parameterToReplace", parameterToReplace); ArgumentUtility.CheckNotNull("expression", expression); ArgumentUtility.CheckNotNull("context", context); var clause = GetQuerySourceForNode(referencedNode, context); var referenceExpression = new QuerySourceReferenceExpression(clause); return(ReplacingExpressionVisitor.Replace(parameterToReplace, referenceExpression, expression)); }
public void SetUp() { _querySource = ExpressionHelper.CreateMainFromClause_Int(); _sourceExpression = new QuerySourceReferenceExpression(_querySource); var originalFunc = ExpressionHelper.CreateLambdaExpression <int, int, int> ((total, i) => total + i); _func = Expression.Lambda( ReplacingExpressionVisitor.Replace(originalFunc.Parameters[1], _sourceExpression, originalFunc.Body), originalFunc.Parameters[0]); _resultSelector = ExpressionHelper.CreateLambdaExpression <int, string> (total => total.ToString()); _seed = Expression.Constant(12); _resultOperatorWithoutResultSelector = new AggregateFromSeedResultOperator(_seed, _func, null); _resultOperatorWithResultSelector = new AggregateFromSeedResultOperator(_seed, _func, _resultSelector); }
private static Expression CreateSnapshotValueExpression(Expression expression, IPropertyBase propertyBase) { if (propertyBase is IProperty property) { var comparer = property.GetValueComparer() ?? property.FindMapping()?.Comparer; if (comparer != null) { expression = ReplacingExpressionVisitor.Replace( comparer.SnapshotExpression.Parameters.Single(), expression, comparer.SnapshotExpression.Body); } } return(expression); }
public override Expression Resolve( ParameterExpression inputParameter, Expression expressionToBeResolved, ClauseGenerationContext clauseGenerationContext) { LinqUtility.CheckNotNull("inputParameter", inputParameter); LinqUtility.CheckNotNull("expressionToBeResolved", expressionToBeResolved); if (IsLetNode) { // We modify the structure of the stream of data coming into this node by our selector, // so we first resolve the selector (adapted to include a reference to the let clause), then we substitute the result for the inputParameter // in the expressionToBeResolved. var resolvedSelector = GetResolvedAdaptedSelector(clauseGenerationContext); return(ReplacingExpressionVisitor.Replace(inputParameter, resolvedSelector, expressionToBeResolved)); } return(base.Resolve(inputParameter, expressionToBeResolved, clauseGenerationContext)); }
public virtual Expression Inject(Expression expression) { var result = Visit(expression); if (_expressions.All(e => e.NodeType == ExpressionType.Assign)) { result = new ReplacingExpressionVisitor(_expressions.Cast <BinaryExpression>() .ToDictionary(e => e.Left, e => e.Right)).Visit(result); } else { _expressions.Add(result); result = Expression.Block(_variables, _expressions); } return(ConvertToLambda(result, Expression.Parameter(result.Type, "result"))); }
public override Expression CustomizeDataReaderExpression(Expression expression) { if (SpatialConverter is null) { return(expression); } if (expression.Type != SpatialConverter.ProviderClrType) { expression = Expression.Convert(expression, SpatialConverter.ProviderClrType); } return(ReplacingExpressionVisitor.Replace( SpatialConverter.ConvertFromProviderExpression.Parameters.Single(), expression, SpatialConverter.ConvertFromProviderExpression.Body)); }
internal static void AddQueryFilter <T>(this EntityTypeBuilder entityTypeBuilder, Expression <Func <T, bool> > expression) { var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType); var expressionFilter = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), parameterType, expression.Body); var currentQueryFilter = entityTypeBuilder.Metadata.GetQueryFilter(); if (currentQueryFilter != null) { var currentExpressionFilter = ReplacingExpressionVisitor.Replace(currentQueryFilter.Parameters.Single(), parameterType, currentQueryFilter.Body); expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter); } var lambdaExpression = Expression.Lambda(expressionFilter, parameterType); entityTypeBuilder.HasQueryFilter(lambdaExpression); }
protected override ShapedQueryExpression TranslateGroupBy(ShapedQueryExpression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector) { var remappedKeySelector = RemapLambdaBody(source, keySelector); var translatedKey = TranslateGroupingKey(remappedKeySelector); if (translatedKey != null) { if (elementSelector != null) { source = TranslateSelect(source, elementSelector); } var inMemoryQueryExpression = (InMemoryQueryExpression)source.QueryExpression; source.ShaperExpression = inMemoryQueryExpression.ApplyGrouping(translatedKey, source.ShaperExpression); if (resultSelector == null) { return(source); } var keyAccessExpression = Expression.MakeMemberAccess( source.ShaperExpression, source.ShaperExpression.Type.GetTypeInfo().GetMember(nameof(IGrouping <int, int> .Key))[0]); var original1 = resultSelector.Parameters[0]; var original2 = resultSelector.Parameters[1]; var newResultSelectorBody = new ReplacingExpressionVisitor( new Dictionary <Expression, Expression> { { original1, keyAccessExpression }, { original2, source.ShaperExpression } }).Visit(resultSelector.Body); newResultSelectorBody = ExpandWeakEntities(inMemoryQueryExpression, newResultSelectorBody); source.ShaperExpression = _projectionBindingExpressionVisitor.Translate(inMemoryQueryExpression, newResultSelectorBody); inMemoryQueryExpression.PushdownIntoSubquery(); return(source); } return(null); }
private LambdaExpression CombineQueryFilters(Type entityType, LambdaExpression baseFilter, IEnumerable <LambdaExpression> andAlsoExpressions) { var newParam = Expression.Parameter(entityType); var andAlsoExprBase = (Expression <Func <IEntity, bool> >)(_ => true); var andAlsoExpr = ReplacingExpressionVisitor.Replace(andAlsoExprBase.Parameters.Single(), newParam, andAlsoExprBase.Body); foreach (var expressionBase in andAlsoExpressions) { var expression = ReplacingExpressionVisitor.Replace(expressionBase.Parameters.Single(), newParam, expressionBase.Body); andAlsoExpr = Expression.AndAlso(andAlsoExpr, expression); } var baseExp = ReplacingExpressionVisitor.Replace(baseFilter.Parameters.Single(), newParam, baseFilter.Body); var exp = Expression.OrElse(baseExp, andAlsoExpr); return(Expression.Lambda(exp, newParam)); }
internal static void AddQueryFilter(this EntityTypeBuilder entityTypeBuilder, LambdaExpression expression) { var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType); var expressionFilter = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), parameterType, expression.Body); //var internalEntityTypeBuilder = entityTypeBuilder.GetInternalEntityTypeBuilder(); //if (internalEntityTypeBuilder.Metadata.QueryFilter != null) //{ // var currentQueryFilter = internalEntityTypeBuilder.Metadata.QueryFilter; // var currentExpressionFilter = ReplacingExpressionVisitor.Replace( // currentQueryFilter.Parameters.Single(), parameterType, currentQueryFilter.Body); // expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter); //} var lambdaExpression = Expression.Lambda(expressionFilter, parameterType); entityTypeBuilder.HasQueryFilter(lambdaExpression); }
private Expression GetSelector(MethodCallExpression methodCallExpression, GroupByShaperExpression groupByShaperExpression) { if (methodCallExpression.Arguments.Count == 1) { return(groupByShaperExpression.ElementSelector); } if (methodCallExpression.Arguments.Count == 2) { var selectorLambda = methodCallExpression.Arguments[1].UnwrapLambdaFromQuote(); return(ReplacingExpressionVisitor.Replace( selectorLambda.Parameters[0], groupByShaperExpression.ElementSelector, selectorLambda.Body)); } throw new InvalidOperationException(); }
/// <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 Expression VisitConstant(ConstantExpression constantExpression) { if (constantExpression.IsEntityQueryable()) { var type = ((IQueryable)constantExpression.Value).ElementType; var entityType = _queryCompilationContext.Model.FindEntityType(type)?.RootType(); if (entityType?.QueryFilter != null) { var parameterizedFilter = (LambdaExpression)_queryModelGenerator .ExtractParameters( _queryCompilationContext.Logger, entityType.QueryFilter, _parameters, parameterize: false, generateContextAccessors: true); var oldParameterExpression = parameterizedFilter.Parameters[0]; var newParameterExpression = Expression.Parameter(type, oldParameterExpression.Name); var predicateExpression = ReplacingExpressionVisitor .Replace( oldParameterExpression, newParameterExpression, parameterizedFilter.Body); var whereExpression = Expression.Call( _whereMethod.MakeGenericMethod(type), constantExpression, Expression.Lambda( predicateExpression, newParameterExpression)); var subQueryModel = _queryModelGenerator.ParseQuery(whereExpression); return(new SubQueryExpression(subQueryModel)); } } return(constantExpression); }
protected override Expression VisitConditional(ConditionalExpression conditionalExpression) { var test = Visit(conditionalExpression.Test); if (test is BinaryExpression binaryTest && (binaryTest.NodeType == ExpressionType.Equal || binaryTest.NodeType == ExpressionType.NotEqual)) { var isLeftNullConstant = IsNullConstant(binaryTest.Left); var isRightNullConstant = IsNullConstant(binaryTest.Right); if ((isLeftNullConstant == isRightNullConstant) || (binaryTest.NodeType == ExpressionType.Equal && !IsNullConstant(conditionalExpression.IfTrue)) || (binaryTest.NodeType == ExpressionType.NotEqual && !IsNullConstant(conditionalExpression.IfFalse))) { return(conditionalExpression); } var caller = isLeftNullConstant ? binaryTest.Right : binaryTest.Left; var accessOperation = binaryTest.NodeType == ExpressionType.Equal ? conditionalExpression.IfFalse : conditionalExpression.IfTrue; // Unwrap nested nullConditional if (caller is NullConditionalExpression nullConditionalCaller) { accessOperation = ReplacingExpressionVisitor.Replace( _nullConditionalRemovingExpressionVisitor.Visit(nullConditionalCaller.AccessOperation), nullConditionalCaller, accessOperation); } if (_nullSafeAccessVerifyingExpressionVisitor.Verify(caller, accessOperation)) { return(new NullConditionalExpression(caller, accessOperation)); } } return(base.VisitConditional(conditionalExpression)); }
/// <summary> /// Reduces the node and then calls the visitor delegate on the reduced expression. /// The method throws an exception if the node is not /// reducible. /// </summary> /// <returns> /// The expression being visited, or an expression which should replace it in the tree. /// </returns> /// <param name="visitor">An instance of <see cref="T:System.Func`2" />.</param> protected override Expression VisitChildren(ExpressionVisitor visitor) { var newNullableCaller = visitor.Visit(NullableCaller); var newCaller = visitor.Visit(Caller); var newAccessOperation = visitor.Visit( ReplacingExpressionVisitor .Replace(Caller, newCaller, AccessOperation)); if (newNullableCaller != NullableCaller || newCaller != Caller || newAccessOperation != AccessOperation) { return(new NullConditionalExpression( newNullableCaller, newCaller, newAccessOperation)); } return(this); }
private static Expression CreateGetStoreValueExpression( Expression jObjectExpression, string storeName, CoreTypeMapping typeMapping, Type clrType) { var jTokenExpression = Expression.Call(jObjectExpression, _getItemMethodInfo, Expression.Constant(storeName)); Expression valueExpression; var converter = typeMapping.Converter; if (converter != null) { valueExpression = ConvertJTokenToType(jTokenExpression, converter.ProviderClrType); valueExpression = ReplacingExpressionVisitor.Replace( converter.ConvertFromProviderExpression.Parameters.Single(), valueExpression, converter.ConvertFromProviderExpression.Body); if (valueExpression.Type != clrType) { valueExpression = Expression.Convert(valueExpression, clrType); } } else { valueExpression = ConvertJTokenToType(jTokenExpression, clrType); } if (clrType.IsNullableType()) { valueExpression = Expression.Condition( Expression.Call(_isNullMethodInfo, jTokenExpression), Expression.Default(valueExpression.Type), valueExpression); } return(valueExpression); }
/// <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 ShapedQueryExpression TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) { if (selector.Body == selector.Parameters[0]) { return(source); } var selectExpression = (SelectExpression)source.QueryExpression; if (selectExpression.IsDistinct) { throw new InvalidOperationException(); } var newSelectorBody = ReplacingExpressionVisitor.Replace(selector.Parameters.Single(), source.ShaperExpression, selector.Body); source.ShaperExpression = _projectionBindingExpressionVisitor .Translate(selectExpression, newSelectorBody); return(source); }
public static void UseSoftDelete(this DbContext context, ModelBuilder modelBuilder) { modelBuilder.Model.GetEntityTypes() .Where(entityType => typeof(ISoftDelete).IsAssignableFrom(entityType.ClrType)) .ToList() .ForEach(entityType => { modelBuilder.Entity(entityType.ClrType) .HasQueryFilter(ConvertFilterExpression <ISoftDelete>(x => !x.IsDeleted, entityType.ClrType)); }); LambdaExpression ConvertFilterExpression <TInterface>( Expression <Func <TInterface, bool> > filterExpression, Type entityType) { var newParam = Expression.Parameter(entityType, filterExpression.Parameters[0].Name); var newBody = ReplacingExpressionVisitor.Replace(filterExpression.Parameters.Single(), newParam, filterExpression.Body); return(Expression.Lambda(newBody, newParam)); } }
/// <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 ShapedQueryExpression TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) { Check.NotNull(source, nameof(source)); Check.NotNull(selector, nameof(selector)); if (selector.Body == selector.Parameters[0]) { return(source); } var selectExpression = (SelectExpression)source.QueryExpression; if (selectExpression.IsDistinct) { return(null); } var newSelectorBody = ReplacingExpressionVisitor.Replace(selector.Parameters.Single(), source.ShaperExpression, selector.Body); return(source.UpdateShaperExpression(_projectionBindingExpressionVisitor.Translate(selectExpression, newSelectorBody))); }