public override DbExpression Visit(DbScanExpression expression) { var globalFilters = expression.Target.ElementType.MetadataProperties.Where( mp => mp.Name.Contains("customannotation:globalFilter_")).ToList(); if (!globalFilters.Any()) { return(base.Visit(expression)); } DbExpression current = expression; foreach (var globalFilter in globalFilters) { var convention = (FilterDefinition)globalFilter.Value; Filter filterConfig; string filterName = globalFilter.Name.Split(new[] { "customannotation:globalFilter_" }, StringSplitOptions.None)[1]; if (!FilterExtensions.FilterConfigurations.TryGetValue(new Tuple <string, object>(filterName, _contextForInterception.GetInternalContext()), out filterConfig)) { continue; } if (!filterConfig.IsEnabled) { continue; } var linqExpression = convention.Predicate(_contextForInterception, filterConfig.ParameterValues); var funcletizerType = typeof(DefaultExpressionVisitor).Assembly.GetType( "System.Data.Entity.Core.Objects.ELinq.Funcletizer"); var funcletizerFactoryMethod = funcletizerType.GetMethod("CreateQueryFuncletizer", BindingFlags.Static | BindingFlags.NonPublic); var funcletizer = funcletizerFactoryMethod.Invoke(null, new[] { _objectContext }); var converterType = typeof(DefaultExpressionVisitor).Assembly.GetType( "System.Data.Entity.Core.Objects.ELinq.ExpressionConverter"); var converter = Activator.CreateInstance(converterType, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { funcletizer, linqExpression }, null); var convertMethod = converterType.GetMethod("Convert", BindingFlags.NonPublic | BindingFlags.Instance); var result = (DbFilterExpression)convertMethod.Invoke(converter, null); var binding = current.Bind(); var normalizer = new BindingNormalizer(binding); var output = result.Predicate.Accept(normalizer); current = binding.Filter(output); } return(current); }
private DbExpression TransformIntersectOrExcept( DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList <DbPropertyExpression> sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { bool flag1 = expressionKind == DbExpressionKind.Except || expressionKind == DbExpressionKind.Skip; bool flag2 = expressionKind == DbExpressionKind.Except || expressionKind == DbExpressionKind.Intersect; DbExpressionBinding input = left.Bind(); DbExpressionBinding expressionBinding = right.Bind(); IList <DbPropertyExpression> propertyExpressionList1 = (IList <DbPropertyExpression>) new List <DbPropertyExpression>(); IList <DbPropertyExpression> propertyExpressionList2 = (IList <DbPropertyExpression>) new List <DbPropertyExpression>(); this.FlattenProperties((DbExpression)input.Variable, propertyExpressionList1); this.FlattenProperties((DbExpression)expressionBinding.Variable, propertyExpressionList2); if (expressionKind == DbExpressionKind.Skip && Sql8ExpressionRewriter.RemoveNonSortProperties(propertyExpressionList1, propertyExpressionList2, sortExpressionsOverLeft, input.VariableName, sortExpressionsBindingVariableName)) { expressionBinding = Sql8ExpressionRewriter.CapWithProject(expressionBinding, propertyExpressionList2); } DbExpression dbExpression1 = (DbExpression)null; for (int index = 0; index < propertyExpressionList1.Count; ++index) { DbExpression right1 = (DbExpression)propertyExpressionList1[index].Equal((DbExpression)propertyExpressionList2[index]).Or((DbExpression)propertyExpressionList1[index].IsNull().And((DbExpression)propertyExpressionList2[index].IsNull())); dbExpression1 = index != 0 ? (DbExpression)dbExpression1.And(right1) : right1; } DbExpression dbExpression2 = (DbExpression)expressionBinding.Any(dbExpression1); DbExpression predicate = !flag1 ? dbExpression2 : (DbExpression)dbExpression2.Not(); DbExpression dbExpression3 = (DbExpression)input.Filter(predicate); if (flag2) { dbExpression3 = (DbExpression)dbExpression3.Distinct(); } return(dbExpression3); }
/// <summary> /// This method is used for translating <see cref="DbIntersectExpression"/> and <see cref="DbExceptExpression"/>, /// and for translating the "Except" part of <see cref="DbSkipExpression"/>. /// into the follwoing expression: /// /// A INTERSECT B, A EXCEPT B /// /// (DISTINCT) /// | /// FILTER /// | /// | - Input: A /// | - Predicate:(NOT) /// | /// ANY /// | /// | - Input: B /// | - Predicate: (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) /// AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) /// AND ... /// AND (B.bn = A.an or (B.bn is null and A.an is null))) /// /// Here, A corresponds to right and B to left. /// (NOT) is present when transforming Except /// for the purpose of translating <see cref="DbExceptExpression"/> or <see cref="DbSkipExpression"/>. /// (DISTINCT) is present when transforming for the purpose of translating /// <see cref="DbExceptExpression"/> or <see cref="DbIntersectExpression"/>. /// /// For <see cref="DbSkipExpression"/>, the input to ANY is caped with project which projects out only /// the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate. /// This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these. /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <param name="expressionKind"></param> /// <param name="sortExpressionsOverLeft">note that this list gets destroyed by this method</param> /// <param name="sortExpressionsBindingVariableName"></param> /// <returns></returns> private DbExpression TransformIntersectOrExcept( DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList<DbPropertyExpression> sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { var negate = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip); var distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect); var leftInputBinding = left.Bind(); var rightInputBinding = right.Bind(); IList<DbPropertyExpression> leftFlattenedProperties = new List<DbPropertyExpression>(); IList<DbPropertyExpression> rightFlattenedProperties = new List<DbPropertyExpression>(); FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties); FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties); //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and // the properties in the list sortExpressionsOverLeft // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these // are non equal comparable, SQL Server 2000 throws. if (expressionKind == DbExpressionKind.Skip) { if (RemoveNonSortProperties( leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName, sortExpressionsBindingVariableName)) { rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties); } } Debug.Assert( leftFlattenedProperties.Count == rightFlattenedProperties.Count, "The left and the right input to INTERSECT or EXCEPT have a different number of properties"); Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties"); //Build the predicate for the quantifier: // (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) DbExpression existsPredicate = null; for (var i = 0; i < leftFlattenedProperties.Count; i++) { //A.ai == B.bi DbExpression equalsExpression = leftFlattenedProperties[i].Equal(rightFlattenedProperties[i]); //A.ai is null AND B.bi is null DbExpression leftIsNullExpression = leftFlattenedProperties[i].IsNull(); DbExpression rightIsNullExpression = rightFlattenedProperties[i].IsNull(); DbExpression bothNullExpression = leftIsNullExpression.And(rightIsNullExpression); DbExpression orExpression = equalsExpression.Or(bothNullExpression); if (i == 0) { existsPredicate = orExpression; } else { existsPredicate = existsPredicate.And(orExpression); } } //Build the quantifier DbExpression quantifierExpression = rightInputBinding.Any(existsPredicate); DbExpression filterPredicate; //Negate if needed if (negate) { filterPredicate = quantifierExpression.Not(); } else { filterPredicate = quantifierExpression; } //Build the filter DbExpression result = leftInputBinding.Filter(filterPredicate); //Apply distinct in needed if (distinct) { result = result.Distinct(); } return result; }
public override DbExpression Visit(DbScanExpression expression) { // a bit harder to get the metadata in CSpace var item = expression.Target.ElementType.MetadataProperties.First(p => p.Name == "Configuration"); // using reflection to get the Annotations property as EntityTtypeConfiguration is an internal class in EF Dictionary <string, object> annotations = new Dictionary <string, object>(); var value = item.Value; var propertyInfo = value.GetType().GetProperty("Annotations"); if (propertyInfo != null) { annotations = (Dictionary <string, object>)propertyInfo.GetValue(value, null); } if (!annotations.Any()) { return(base.Visit(expression)); } DbExpression current = expression; foreach (var globalFilter in annotations.Where(a => a.Key.StartsWith("globalFilter"))) { var convention = (FilterDefinition)globalFilter.Value; Filter filterConfig; string filterName = globalFilter.Key.Split(new[] { "globalFilter_" }, StringSplitOptions.None)[1]; if (!FilterExtensions.FilterConfigurations.TryGetValue(new Tuple <string, object>(filterName, _contextForInterception.GetInternalContext()), out filterConfig)) { continue; } if (!filterConfig.IsEnabled) { continue; } var linqExpression = convention.Predicate(_contextForInterception, filterConfig.ParameterValues); var funcletizerType = typeof(DefaultExpressionVisitor).Assembly.GetType( "System.Data.Entity.Core.Objects.ELinq.Funcletizer"); var funcletizerFactoryMethod = funcletizerType.GetMethod("CreateQueryFuncletizer", BindingFlags.Static | BindingFlags.NonPublic); var funcletizer = funcletizerFactoryMethod.Invoke(null, new[] { _objectContext }); var converterType = typeof(DefaultExpressionVisitor).Assembly.GetType( "System.Data.Entity.Core.Objects.ELinq.ExpressionConverter"); var converter = Activator.CreateInstance(converterType, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { funcletizer, linqExpression }, null); var convertMethod = converterType.GetMethod("Convert", BindingFlags.NonPublic | BindingFlags.Instance); var result = (DbFilterExpression)convertMethod.Invoke(converter, null); var binding = current.Bind(); var normalizer = new BindingNormalizer(binding); var output = result.Predicate.Accept(normalizer); current = binding.Filter(output); } return(current); }
// <summary> // This method is used for translating <see cref="DbIntersectExpression" /> and <see cref="DbExceptExpression" />, // and for translating the "Except" part of <see cref="DbSkipExpression" />. // into the follwoing expression: // A INTERSECT B, A EXCEPT B // (DISTINCT) // | // FILTER // | // | - Input: A // | - Predicate:(NOT) // | // ANY // | // | - Input: B // | - Predicate: (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) // Here, A corresponds to right and B to left. // (NOT) is present when transforming Except // for the purpose of translating <see cref="DbExceptExpression" /> or <see cref="DbSkipExpression" />. // (DISTINCT) is present when transforming for the purpose of translating // <see cref="DbExceptExpression" /> or <see cref="DbIntersectExpression" />. // For <see cref="DbSkipExpression" />, the input to ANY is caped with project which projects out only // the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate. // This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these. // </summary> // <param name="sortExpressionsOverLeft"> note that this list gets destroyed by this method </param> private DbExpression TransformIntersectOrExcept( DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList <DbPropertyExpression> sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { var negate = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip); var distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect); var leftInputBinding = left.Bind(); var rightInputBinding = right.Bind(); IList <DbPropertyExpression> leftFlattenedProperties = new List <DbPropertyExpression>(); IList <DbPropertyExpression> rightFlattenedProperties = new List <DbPropertyExpression>(); FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties); FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties); //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and // the properties in the list sortExpressionsOverLeft // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these // are non equal comparable, SQL Server 2000 throws. if (expressionKind == DbExpressionKind.Skip) { if (RemoveNonSortProperties( leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName, sortExpressionsBindingVariableName)) { rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties); } } Debug.Assert( leftFlattenedProperties.Count == rightFlattenedProperties.Count, "The left and the right input to INTERSECT or EXCEPT have a different number of properties"); Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties"); //Build the predicate for the quantifier: // (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) DbExpression existsPredicate = null; for (var i = 0; i < leftFlattenedProperties.Count; i++) { //A.ai == B.bi DbExpression equalsExpression = leftFlattenedProperties[i].Equal(rightFlattenedProperties[i]); //A.ai is null AND B.bi is null DbExpression leftIsNullExpression = leftFlattenedProperties[i].IsNull(); DbExpression rightIsNullExpression = rightFlattenedProperties[i].IsNull(); DbExpression bothNullExpression = leftIsNullExpression.And(rightIsNullExpression); DbExpression orExpression = equalsExpression.Or(bothNullExpression); if (i == 0) { existsPredicate = orExpression; } else { existsPredicate = existsPredicate.And(orExpression); } } //Build the quantifier DbExpression quantifierExpression = rightInputBinding.Any(existsPredicate); DbExpression filterPredicate; //Negate if needed if (negate) { filterPredicate = quantifierExpression.Not(); } else { filterPredicate = quantifierExpression; } //Build the filter DbExpression result = leftInputBinding.Filter(filterPredicate); //Apply distinct in needed if (distinct) { result = result.Distinct(); } return(result); }