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);
        }
Exemple #2
0
        private void MapEqualsExpression(MethodCallExpression expression)
        {
            if ((expression.Arguments == null) || (expression.Arguments.Count != 1))
            {
                throw new ApplicationException("Did not find exactly 1 Argument to Equals function");
            }

            DbExpression srcExpression = GetDbExpressionForExpression(expression.Object);

            DbExpression dbExpression;

            if (expression.Arguments[0] is ConstantExpression)
            {
                var constantExpression = GetDbExpressionForExpression(expression.Arguments[0]) as DbConstantExpression;
                if ((constantExpression == null) || (constantExpression.Value == null))
                {
                    throw new NullReferenceException("Parameter to Equals cannot be null");
                }

                dbExpression = DbExpressionBuilder.Equal(srcExpression, constantExpression);
            }
            else
            {
                var argExpression = GetDbExpressionForExpression(expression.Arguments[0]);

                //  Note: Can also do this using StartsWith function on srcExpression (which avoids having to hardcode the % character).
                //  It works but generates some crazy conditions using charindex which I don't think will use indexes as well as "like"...
                //dbExpression = DbExpressionBuilder.Equal(DbExpressionBuilder.True, srcExpression.StartsWith(argExpression));

                //dbExpression = DbExpressionBuilder.Equal(srcExpression, argExpression);
                dbExpression = srcExpression.Equal(argExpression);
            }

            MapExpressionToDbExpression(expression, dbExpression);
        }
        /// <summary>
        /// Creates an Equal comparison of a nullable property (db column) to a nullable parameter (lambda param)
        /// that adds the necessary "is null" checks to support a filter like "e.TenantId = tenantId".
        /// Results in sql: (e.TenantID is null and @tenantID is null) or (e.TenantID is not null and e.TenantID = @tenantID)
        /// which will support parmeter values that are "null" or a specific value and will correctly filter on columns that
        /// are "null" or a specific value.
        /// </summary>
        /// <param name="propExpression"></param>
        /// <param name="paramExpression"></param>
        /// <returns></returns>
        private DbExpression CreateEqualComparisonOfNullablePropToNullableParam(DbExpression propExpression, DbExpression paramExpression)
        {
            var condition1 = propExpression.IsNull().And(paramExpression.IsNull());
            var condition2 = propExpression.IsNull().Not().And(propExpression.Equal(paramExpression));

            return(condition1.Or(condition2));
        }
        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);
        }
        ComplexObjectModel GenComplexObjectModel(ComplexPropertyDescriptor navigationDescriptor, NavigationNode navigationNode, QueryModel queryModel)
        {
            TypeDescriptor navigationTypeDescriptor = EntityTypeContainer.GetDescriptor(navigationDescriptor.PropertyType);

            DbTable           dbTable      = navigationTypeDescriptor.Table;
            DbTableExpression tableExp     = new DbTableExpression(dbTable);
            string            alias        = queryModel.GenerateUniqueTableAlias(dbTable.Name);
            DbTableSegment    joinTableSeg = new DbTableSegment(tableExp, alias, queryModel.FromTable.Table.Lock);

            DbTable            aliasTable            = new DbTable(alias);
            ComplexObjectModel navigationObjectModel = navigationTypeDescriptor.GenObjectModel(aliasTable);

            navigationObjectModel.NullChecking = navigationObjectModel.PrimaryKey;

            PrimitivePropertyDescriptor foreignKeyPropertyDescriptor = navigationDescriptor.ForeignKeyProperty;
            DbExpression          foreignKeyColumn = this.GetPrimitiveMember(foreignKeyPropertyDescriptor.Property);
            DbExpression          joinCondition    = DbExpression.Equal(foreignKeyColumn, navigationObjectModel.PrimaryKey);
            DbJoinTableExpression joinTableExp     = new DbJoinTableExpression(foreignKeyPropertyDescriptor.IsNullable ? DbJoinType.LeftJoin : DbJoinType.InnerJoin, joinTableSeg, joinCondition);

            this.DependentTable.JoinTables.Add(joinTableExp);

            navigationObjectModel.DependentTable = joinTableExp;

            DbExpression condition = this.ParseCondition(navigationNode.Condition, navigationObjectModel, queryModel.ScopeTables);

            //AndWhere的条件放到join条件里去
            joinTableExp.AppendCondition(condition);

            navigationObjectModel.Filter = this.ParseCondition(navigationNode.Filter, navigationObjectModel, queryModel.ScopeTables);

            //queryModel.Filters.Add(navigationObjectModel.Filter);

            return(navigationObjectModel);
        }
        // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the
        // value is null, creates an IsNull expression
        // Requires: all arguments are set
        private DbExpression GenerateEqualityExpression(DbExpressionBinding target, EdmProperty property, PropagatorResult value)
        {
            Debug.Assert(null != target && null != property && null != value);

            DbExpression propertyExpression = GeneratePropertyExpression(target, property);
            DbExpression valueExpression    = GenerateValueExpression(property, value);

            if (valueExpression.ExpressionKind == DbExpressionKind.Null)
            {
                return(propertyExpression.IsNull());
            }
            return(propertyExpression.Equal(valueExpression));
        }
Exemple #7
0
        private DbExpression GeneratePredicate(StorageConditionPropertyMapping condition, DbExpression row)
        {
            Debug.Assert(condition.EdmProperty == null, "C-side conditions are not supported in function mappings.");
            DbExpression columnRef = GenerateColumnRef(row, condition.ColumnProperty);

            if (condition.IsNull.HasValue)
            {
                return(condition.IsNull.Value ? (DbExpression)columnRef.IsNull() : (DbExpression)columnRef.IsNull().Not());
            }
            else
            {
                return(columnRef.Equal(columnRef.ResultType.Constant(condition.Value)));
            }
        }
Exemple #8
0
        private DbExpression GenerateEqualityExpression(
            DbExpressionBinding target,
            EdmProperty property,
            PropagatorResult value)
        {
            DbExpression propertyExpression = UpdateCompiler.GeneratePropertyExpression(target, property);
            DbExpression valueExpression    = this.GenerateValueExpression(property, value);

            if (valueExpression.ExpressionKind == DbExpressionKind.Null)
            {
                return((DbExpression)propertyExpression.IsNull());
            }
            return((DbExpression)propertyExpression.Equal(valueExpression));
        }
Exemple #9
0
        private static DbExpression GeneratePredicate(
            ConditionPropertyMapping condition,
            DbExpression row)
        {
            DbExpression columnRef = FunctionImportMappingComposable.GenerateColumnRef(row, condition.Column);

            if (!condition.IsNull.HasValue)
            {
                return((DbExpression)columnRef.Equal((DbExpression)columnRef.ResultType.Constant(condition.Value)));
            }
            if (!condition.IsNull.Value)
            {
                return((DbExpression)columnRef.IsNull().Not());
            }
            return((DbExpression)columnRef.IsNull());
        }
        ComplexObjectModel GenCollectionElementObjectModel(TypeDescriptor elementTypeDescriptor, NavigationNode navigationNode, QueryModel queryModel)
        {
            DbTable           dbTable      = elementTypeDescriptor.Table;
            DbTableExpression tableExp     = new DbTableExpression(dbTable);
            string            alias        = queryModel.GenerateUniqueTableAlias(dbTable.Name);
            DbTableSegment    joinTableSeg = new DbTableSegment(tableExp, alias, queryModel.FromTable.Table.Lock);

            DbTable            aliasTable         = new DbTable(alias);
            ComplexObjectModel elementObjectModel = elementTypeDescriptor.GenObjectModel(aliasTable);

            elementObjectModel.NullChecking = elementObjectModel.PrimaryKey;

            ComplexPropertyDescriptor navigationDescriptor = elementTypeDescriptor.ComplexPropertyDescriptors.Where(a => a.PropertyType == this.ObjectType).FirstOrDefault();

            if (navigationDescriptor == null)
            {
                throw new ChloeException($"You have to define a navigation property which type is '{this.ObjectType.FullName}' on class '{elementTypeDescriptor.Definition.Type.FullName}'.");
            }

            DbExpression          elementForeignKeyColumn = elementObjectModel.GetPrimitiveMember(navigationDescriptor.ForeignKeyProperty.Property);
            DbExpression          joinCondition           = DbExpression.Equal(this.PrimaryKey, elementForeignKeyColumn);
            DbJoinTableExpression joinTableExp            = new DbJoinTableExpression(DbJoinType.LeftJoin, joinTableSeg, joinCondition);

            this.DependentTable.JoinTables.Add(joinTableExp);

            elementObjectModel.DependentTable = joinTableExp;
            var condition = this.ParseCondition(navigationNode.Condition, elementObjectModel, queryModel.ScopeTables);

            //AndWhere的条件放到join条件里去
            joinTableExp.AppendCondition(condition);

            elementObjectModel.Filter = this.ParseCondition(navigationNode.Filter, elementObjectModel, queryModel.ScopeTables);

            bool orderByPrimaryKeyExists = queryModel.Orderings.Where(a => a.Expression == this.PrimaryKey).Any();

            if (!orderByPrimaryKeyExists)
            {
                //结果集分组
                DbOrdering ordering = new DbOrdering(this.PrimaryKey, DbOrderType.Asc);
                queryModel.Orderings.Add(ordering);
            }

            //queryModel.Filters.Add(elementObjectModel.Filter);

            return(elementObjectModel);
        }
        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);
        }
Exemple #12
0
        public void Process(DbMethodCallExpression exp, SqlGenerator generator)
        {
            MethodInfo method = exp.Method;

            if (method.DeclaringType == UtilConstants.TypeOfSql)
            {
                Method_Sql_Equals(exp, generator);
                return;
            }

            DbExpression right = exp.Arguments[0];

            if (right.Type != exp.Object.Type)
            {
                right = DbExpression.Convert(right, exp.Object.Type);
            }

            DbExpression.Equal(exp.Object, right).Accept(generator);
        }
        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);
        }
        private void MapContainsExpression(MethodCallExpression expression)
        {
            DbExpression argExpression = GetDbExpressionForExpression(expression.Arguments[0]);

            DbExpression dbExpression;

            var collectionObjExp = expression.Object as ParameterExpression;

            if (collectionObjExp != null)
            {
                //  collectionObjExp is a parameter expression.  This means the content of the collection is
                //  dynamic.  DbInExpression only supports a fixed size list of constant values.
                //  So the only way to handle a dynamic collection is for us to create a single Equals expression
                //  with a DbParameterReference.  Then when we intercept that parameter, we will see that it's
                //  for a collection and we will modify the SQL to change it from an "=" to an "in".  The single
                //  Parameter Reference is set to the first value in the collection and the rest of the values
                //  are inserted into the SQL "in" clause.
                string paramName = collectionObjExp.Name;
                Type   paramType = PrimitiveTypeForType(collectionObjExp.Type);

                var param = CreateParameter(paramName, paramType);
                dbExpression = argExpression.Equal(param);
            }
            else
            {
                var listExpression = expression.Object as ListInitExpression;
                if (listExpression == null)
                {
                    throw new NotSupportedException(string.Format("Unsupported object type used in Contains() - type = {0}", expression.Object.GetType().Name));
                }

                //  This is a fixed size list that may contain parameter references or constant values.
                //  This can be handled using either a DbInExpression (if all are constants) or with
                //  a series of OR conditions.
                //  Find all of the constant & parameter expressions.
                var constantExpressionList = listExpression.Initializers
                                             .Select(i => i.Arguments.FirstOrDefault() as ConstantExpression)
                                             .Where(c => (c != null) && (c.Value != null)) //  null not supported - can only use DbConstant in "In" expression
                                             .Select(c => CreateConstantExpression(c.Value))
                                             .ToList();
                constantExpressionList.AddRange(listExpression.Initializers
                                                .Select(i => i.Arguments.FirstOrDefault() as UnaryExpression)
                                                .Where(c => (c != null) && (c.Operand is ConstantExpression))
                                                .Select(c => CreateConstantExpression(((ConstantExpression)c.Operand).Value)));
                var parameterExpressionList = listExpression.Initializers
                                              .Select(i => i.Arguments.FirstOrDefault() as ParameterExpression)
                                              .Where(c => c != null)
                                              .Select(c => CreateParameter(c.Name, c.Type))
                                              .ToList();

                if (constantExpressionList.Count + parameterExpressionList.Count != listExpression.Initializers.Count)
                {
                    throw new NotSupportedException(string.Format("Unrecognized parameters in Contains list.  Null parameters not supported."));
                }

                if (parameterExpressionList.Any())
                {
                    //  Have parameters so need to build a series of OR conditions so that we can include the
                    //  DbParameterReferences.  EF will optimize this into an "in" condition but with our
                    //  DbParameterReferences preserved (which is not possible with a DbInExpression).
                    //  The DbParameterReferences will be intercepted as any other parameter.
                    dbExpression = null;
                    var allExpressions = parameterExpressionList.Cast <DbExpression>().Union(constantExpressionList.Cast <DbExpression>());
                    foreach (var paramReference in allExpressions)
                    {
                        var equalsExpression = argExpression.Equal(paramReference);
                        if (dbExpression == null)
                        {
                            dbExpression = equalsExpression;
                        }
                        else
                        {
                            dbExpression = dbExpression.Or(equalsExpression);
                        }
                    }
                }
                else
                {
                    //  All values are constants so can use DbInExpression
                    dbExpression = argExpression.In(constantExpressionList);
                }
            }

            MapExpressionToDbExpression(expression, dbExpression);
        }
 // Generate an equality expression where the values of the left and right operands are completely unknown 
 private DbExpression ImplementEqualityUnknownArguments(DbExpression left, DbExpression right, EqualsPattern pattern)
 {
     switch (pattern)
     {
         case EqualsPattern.Store: // left EQ right
             return left.Equal(right);
         case EqualsPattern.PositiveNullEqualityNonComposable: // for Joins
             return left.Equal(right).Or(left.IsNull().And(right.IsNull()));
         case EqualsPattern.PositiveNullEqualityComposable:
             {
                 var bothNotNull = left.Equal(right);
                 var bothNull = left.IsNull().And(right.IsNull());
                 if (!_funcletizer.RootContext.ContextOptions.UseCSharpNullComparisonBehavior)
                 {
                     return bothNotNull.Or(bothNull); // same as EqualsPattern.PositiveNullEqualityNonComposable
                 }
                 // add more logic to avoid undefined result for true clr semantics, ensuring composability
                 // (left EQ right AND NOT (left IS NULL OR right IS NULL)) OR (left IS NULL AND right IS NULL)
                 var anyOneIsNull = left.IsNull().Or(right.IsNull());
                 return (bothNotNull.And(anyOneIsNull.Not())).Or(bothNull);
             }
         default:
             Debug.Fail("unexpected pattern");
             return null;
     }
 }
 // For comparisons, where the left and right side are nullable or not nullable, 
 // here are the (compositionally safe) null equality predicates:
 // -- x NOT NULL, y NULL
 // x = y AND  NOT (y IS NULL)
 // -- x NULL, y NULL
 // (x = y AND  (NOT (x IS NULL OR y IS NULL))) OR (x IS NULL AND y IS NULL)
 // -- x NOT NULL, y NOT NULL
 // x = y
 // -- x NULL, y NOT NULL
 // x = y AND  NOT (x IS NULL)
 private DbExpression ImplementEquality(DbExpression left, DbExpression right, EqualsPattern pattern)
 {
     switch (left.ExpressionKind)
     {
         case DbExpressionKind.Constant:
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant: // constant EQ constant
                     return left.Equal(right);
                 case DbExpressionKind.Null: // null EQ constant --> false
                     return DbExpressionBuilder.False;
                 default:
                     return ImplementEqualityConstantAndUnknown((DbConstantExpression)left, right, pattern);
             }
         case DbExpressionKind.Null:
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant: // null EQ constant --> false
                     return DbExpressionBuilder.False;
                 case DbExpressionKind.Null: // null EQ null --> true
                     return DbExpressionBuilder.True;
                 default: // null EQ right --> right IS NULL
                     return right.IsNull();
             }
         default: // unknown
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant:
                     return ImplementEqualityConstantAndUnknown((DbConstantExpression)right, left, pattern);
                 case DbExpressionKind.Null: //  left EQ null --> left IS NULL
                     return left.IsNull();
                 default:
                     return ImplementEqualityUnknownArguments(left, right, pattern);
             }
     }
 }
Exemple #17
0
        static void StringConcat(DbBinaryExpression exp, SqlGeneratorBase generator)
        {
            List <DbExpression> operands = new List <DbExpression>();

            operands.Add(exp.Right);

            DbExpression    left = exp.Left;
            DbAddExpression e    = null;

            while ((e = (left as DbAddExpression)) != null && (e.Method == PublicConstants.MethodInfo_String_Concat_String_String || e.Method == PublicConstants.MethodInfo_String_Concat_Object_Object))
            {
                operands.Add(e.Right);
                left = e.Left;
            }

            operands.Add(left);

            DbExpression        whenExp     = null;
            List <DbExpression> operandExps = new List <DbExpression>(operands.Count);

            for (int i = operands.Count - 1; i >= 0; i--)
            {
                DbExpression operand = operands[i];
                DbExpression opBody  = operand;
                if (opBody.Type != PublicConstants.TypeOfString)
                {
                    // 需要 cast type
                    opBody = DbExpression.Convert(opBody, PublicConstants.TypeOfString);
                }

                DbExpression equalNullExp = DbExpression.Equal(opBody, PublicConstants.DbConstant_Null_String);

                if (whenExp == null)
                {
                    whenExp = equalNullExp;
                }
                else
                {
                    whenExp = DbExpression.And(whenExp, equalNullExp);
                }

                operandExps.Add(opBody);
            }

            generator.SqlBuilder.Append("CASE", " WHEN ");
            whenExp.Accept(generator);
            generator.SqlBuilder.Append(" THEN ");
            DbConstantExpression.Null.Accept(generator);
            generator.SqlBuilder.Append(" ELSE ");

            generator.SqlBuilder.Append("(");

            for (int i = 0; i < operandExps.Count; i++)
            {
                if (i > 0)
                {
                    generator.SqlBuilder.Append(" + ");
                }

                generator.SqlBuilder.Append("ISNULL(");
                operandExps[i].Accept(generator);
                generator.SqlBuilder.Append(",");
                DbConstantExpression.StringEmpty.Accept(generator);
                generator.SqlBuilder.Append(")");
            }

            generator.SqlBuilder.Append(")");

            generator.SqlBuilder.Append(" END");
        }