internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull) { DbExpression cqt = (DbExpression)null; this.AsCql((Action <NegatedConstant, IEnumerable <Constant> >)((negated, domainValues) => cqt = negated.AsCqt(row, domainValues, this.RestrictedMemberSlot.MemberPath, skipIsNotNull)), (Action <Set <Constant> >)(domainValues => { cqt = this.RestrictedMemberSlot.MemberPath.AsCqt(row); if (domainValues.Count == 1) { cqt = (DbExpression)cqt.Equal(domainValues.Single <Constant>().AsCqt(row, this.RestrictedMemberSlot.MemberPath)); } else { cqt = Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>)domainValues.Select <Constant, DbExpression>((Func <Constant, DbExpression>)(c => (DbExpression)cqt.Equal(c.AsCqt(row, this.RestrictedMemberSlot.MemberPath)))).ToList <DbExpression>(), (Func <DbExpression, DbExpression, DbExpression>)((prev, next) => (DbExpression)prev.Or(next))); } }), (Action)(() => { DbExpression right = (DbExpression)this.RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull().Not(); cqt = cqt != null ? (DbExpression)cqt.And(right) : right; }), (Action)(() => { DbExpression left = (DbExpression)this.RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull(); cqt = cqt != null ? (DbExpression)left.Or(cqt) : left; }), skipIsNotNull); return(cqt); }
public override DbExpression Visit(DbEqualExpression exp) { DbExpression left = exp.Left; DbExpression right = exp.Right; left = DbExpressionExtension.StripInvalidConvert(left); right = DbExpressionExtension.StripInvalidConvert(right); MethodInfo method_Sql_Equals = PublicConstants.MethodInfo_Sql_Equals.MakeGenericMethod(left.Type); /* Sql.Equals(left, right) */ DbMethodCallExpression left_equals_right = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { left, right }); if (right.NodeType == DbExpressionType.Parameter || right.NodeType == DbExpressionType.Constant || left.NodeType == DbExpressionType.Parameter || left.NodeType == DbExpressionType.Constant || right.NodeType == DbExpressionType.SubQuery || left.NodeType == DbExpressionType.SubQuery || !left.Type.CanNull() || !right.Type.CanNull()) { /* * a.Name == name --> a.Name == name * a.Id == (select top 1 T.Id from T) --> a.Id == (select top 1 T.Id from T) * 对于上述查询,我们不考虑 null */ left_equals_right.Accept(this); return(exp); } /* * a.Name == a.XName --> a.Name == a.XName or (a.Name is null and a.XName is null) */ /* Sql.Equals(left, null) */ var left_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { left, DbExpression.Constant(null, left.Type) }); /* Sql.Equals(right, null) */ var right_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { right, DbExpression.Constant(null, right.Type) }); /* Sql.Equals(left, null) && Sql.Equals(right, null) */ var left_is_null_and_right_is_null = DbExpression.And(left_is_null, right_is_null); /* Sql.Equals(left, right) || (Sql.Equals(left, null) && Sql.Equals(right, null)) */ var left_equals_right_or_left_is_null_and_right_is_null = DbExpression.Or(left_equals_right, left_is_null_and_right_is_null); left_equals_right_or_left_is_null_and_right_is_null.Accept(this); return(exp); }
internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull) { DbExpression cqt = null; AsCql( // negatedConstantAsCql action (negated, domainValues) => { Debug.Assert(cqt == null, "unexpected construction order - cqt must be null"); cqt = negated.AsCqt(row, domainValues, RestrictedMemberSlot.MemberPath, skipIsNotNull); }, // varInDomain action (domainValues) => { Debug.Assert(cqt == null, "unexpected construction order - cqt must be null"); Debug.Assert(domainValues.Count > 0, "domain must not be empty"); cqt = RestrictedMemberSlot.MemberPath.AsCqt(row); if (domainValues.Count == 1) { // Single value cqt = cqt.Equal(domainValues.Single().AsCqt(row, RestrictedMemberSlot.MemberPath)); } else { // Multiple values: build list of var = c1, var = c2, ..., then OR them all. var operands = domainValues.Select(c => (DbExpression)cqt.Equal(c.AsCqt(row, RestrictedMemberSlot.MemberPath))).ToList(); cqt = Helpers.BuildBalancedTreeInPlace(operands, (prev, next) => prev.Or(next)); } }, // varIsNotNull action () => { // ( ... AND var IS NOT NULL) DbExpression varIsNotNull = RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull().Not(); cqt = cqt != null ? cqt.And(varIsNotNull) : varIsNotNull; }, // varIsNull action () => { // (var IS NULL OR ...) DbExpression varIsNull = RestrictedMemberSlot.MemberPath.AsCqt(row).IsNull(); cqt = cqt != null ? varIsNull.Or(cqt) : varIsNull; }, skipIsNotNull); return(cqt); }
public void Process(DbMethodCallExpression exp, SqlGenerator generator) { DbExpression e = exp.Arguments.First(); DbEqualExpression equalNullExpression = DbExpression.Equal(e, DbExpression.Constant(null, UtilConstants.TypeOfString)); DbEqualExpression equalEmptyExpression = DbExpression.Equal(e, DbExpression.Constant(string.Empty)); DbOrExpression orExpression = DbExpression.Or(equalNullExpression, equalEmptyExpression); DbCaseWhenExpression.WhenThenExpressionPair whenThenPair = new DbCaseWhenExpression.WhenThenExpressionPair(orExpression, DbConstantExpression.One); List<DbCaseWhenExpression.WhenThenExpressionPair> whenThenExps = new List<DbCaseWhenExpression.WhenThenExpressionPair>(1); whenThenExps.Add(whenThenPair); DbCaseWhenExpression caseWhenExpression = DbExpression.CaseWhen(whenThenExps, DbConstantExpression.Zero, UtilConstants.TypeOfBoolean); var eqExp = DbExpression.Equal(caseWhenExpression, DbConstantExpression.One); eqExp.Accept(generator); }
public override DbExpression Visit(DbNotEqualExpression exp) { DbExpression left = exp.Left; DbExpression right = exp.Right; left = DbExpressionExtension.StripInvalidConvert(left); right = DbExpressionExtension.StripInvalidConvert(right); MethodInfo method_Sql_NotEquals = PublicConstants.MethodInfo_Sql_NotEquals.MakeGenericMethod(left.Type); /* Sql.NotEquals(left, right) */ DbMethodCallExpression left_not_equals_right = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2) { left, right }); //明确 left right 其中一边一定为 null if (DbExpressionExtension.AffirmExpressionRetValueIsNull(right) || DbExpressionExtension.AffirmExpressionRetValueIsNull(left)) { /* * a.Name != null --> a.Name != null */ left_not_equals_right.Accept(this); return(exp); } if (right.NodeType == DbExpressionType.SubQuery || left.NodeType == DbExpressionType.SubQuery) { /* * a.Id != (select top 1 T.Id from T) --> a.Id <> (select top 1 T.Id from T),对于这种查询,我们不考虑 null */ left_not_equals_right.Accept(this); return(exp); } MethodInfo method_Sql_Equals = PublicConstants.MethodInfo_Sql_Equals.MakeGenericMethod(left.Type); if (left.NodeType == DbExpressionType.Parameter || left.NodeType == DbExpressionType.Constant) { var t = right; right = left; left = t; } if (right.NodeType == DbExpressionType.Parameter || right.NodeType == DbExpressionType.Constant) { /* * 走到这说明 name 不可能为 null * a.Name != name --> a.Name <> name or a.Name is null */ if (left.NodeType != DbExpressionType.Parameter && left.NodeType != DbExpressionType.Constant) { /* * a.Name != name --> a.Name <> name or a.Name is null */ /* Sql.Equals(left, null) */ var left_is_null1 = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { left, DbExpression.Constant(null, left.Type) }); /* Sql.NotEquals(left, right) || Sql.Equals(left, null) */ var left_not_equals_right_or_left_is_null = DbExpression.Or(left_not_equals_right, left_is_null1); left_not_equals_right_or_left_is_null.Accept(this); } else { /* * name != name1 --> name <> name,其中 name 和 name1 都为变量且都不可能为 null */ left_not_equals_right.Accept(this); } return(exp); } /* * a.Name != a.XName --> a.Name <> a.XName or (a.Name is null and a.XName is not null) or (a.Name is not null and a.XName is null) * ## a.Name != a.XName 不能翻译成:not (a.Name == a.XName or (a.Name is null and a.XName is null)),因为数据库里的 not 有时候并非真正意义上的“取反”! * 当 a.Name 或者 a.XName 其中一个字段有为 NULL,另一个字段有值时,会查不出此条数据 ## */ DbConstantExpression null_Constant = DbExpression.Constant(null, left.Type); /* Sql.Equals(left, null) */ var left_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { left, null_Constant }); /* Sql.NotEquals(left, null) */ var left_is_not_null = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2) { left, null_Constant }); /* Sql.Equals(right, null) */ var right_is_null = DbExpression.MethodCall(null, method_Sql_Equals, new List <DbExpression>(2) { right, null_Constant }); /* Sql.NotEquals(right, null) */ var right_is_not_null = DbExpression.MethodCall(null, method_Sql_NotEquals, new List <DbExpression>(2) { right, null_Constant }); /* Sql.Equals(left, null) && Sql.NotEquals(right, null) */ var left_is_null_and_right_is_not_null = DbExpression.And(left_is_null, right_is_not_null); /* Sql.NotEquals(left, null) && Sql.Equals(right, null) */ var left_is_not_null_and_right_is_null = DbExpression.And(left_is_not_null, right_is_null); /* (Sql.Equals(left, null) && Sql.NotEquals(right, null)) || (Sql.NotEquals(left, null) && Sql.Equals(right, null)) */ var left_is_null_and_right_is_not_null_or_left_is_not_null_and_right_is_null = DbExpression.Or(left_is_null_and_right_is_not_null, left_is_not_null_and_right_is_null); /* Sql.NotEquals(left, right) || (Sql.Equals(left, null) && Sql.NotEquals(right, null)) || (Sql.NotEquals(left, null) && Sql.Equals(right, null)) */ var e = DbExpression.Or(left_not_equals_right, left_is_null_and_right_is_not_null_or_left_is_not_null_and_right_is_null); e.Accept(this); return(exp); }
// <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); }
protected override Expression VisitBinary(BinaryExpression node) { var expression = base.VisitBinary(node) as BinaryExpression; DbExpression dbExpression; // Need special handling for comparisons against the null constant. If we don't translate these // using an "IsNull" expression, EF will convert it literally as "= null" which doesn't work in SQL Server. if (IsNullConstantExpression(expression.Right)) { dbExpression = MapNullComparison(expression.Left, expression.NodeType); } else if (IsNullConstantExpression(expression.Left)) { dbExpression = MapNullComparison(expression.Right, expression.NodeType); } else { DbExpression leftExpression = GetDbExpressionForExpression(expression.Left); DbExpression rightExpression = GetDbExpressionForExpression(expression.Right); switch (expression.NodeType) { case ExpressionType.Equal: // DbPropertyExpression = class property that has been mapped to a database column // DbParameterReferenceExpression = lambda parameter if (IsNullableExpressionOfType <DbPropertyExpression>(leftExpression) && IsNullableExpressionOfType <DbParameterReferenceExpression>(rightExpression)) { dbExpression = CreateEqualComparisonOfNullablePropToNullableParam(leftExpression, rightExpression); } else if (IsNullableExpressionOfType <DbPropertyExpression>(rightExpression) && IsNullableExpressionOfType <DbParameterReferenceExpression>(leftExpression)) { dbExpression = CreateEqualComparisonOfNullablePropToNullableParam(rightExpression, leftExpression); } else { dbExpression = leftExpression.Equal(rightExpression); } break; case ExpressionType.NotEqual: dbExpression = leftExpression.NotEqual(rightExpression); break; case ExpressionType.GreaterThan: dbExpression = leftExpression.GreaterThan(rightExpression); break; case ExpressionType.GreaterThanOrEqual: dbExpression = leftExpression.GreaterThanOrEqual(rightExpression); break; case ExpressionType.LessThan: dbExpression = leftExpression.LessThan(rightExpression); break; case ExpressionType.LessThanOrEqual: dbExpression = leftExpression.LessThanOrEqual(rightExpression); break; case ExpressionType.AndAlso: dbExpression = leftExpression.And(rightExpression); break; case ExpressionType.OrElse: dbExpression = leftExpression.Or(rightExpression); break; default: throw new NotImplementedException(string.Format("Unhandled NodeType of {0} in LambdaToDbExpressionVisitor.VisitBinary", expression.NodeType)); } } MapExpressionToDbExpression(expression, dbExpression); return(expression); }