Пример #1
0
        private DbExpression BuildPredicate(
            DbExpressionBinding target,
            PropagatorResult referenceRow,
            PropagatorResult current,
            TableChangeProcessor processor,
            ref bool rowMustBeTouched)
        {
            Dictionary <EdmProperty, PropagatorResult> dictionary = new Dictionary <EdmProperty, PropagatorResult>();
            int ordinal = 0;

            foreach (EdmProperty property in processor.Table.ElementType.Properties)
            {
                PropagatorResult memberValue = referenceRow.GetMemberValue(ordinal);
                PropagatorResult input       = current == null ? (PropagatorResult)null : current.GetMemberValue(ordinal);
                if (!rowMustBeTouched && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue)))
                {
                    rowMustBeTouched = true;
                }
                if (!dictionary.ContainsKey(property) && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key)))
                {
                    dictionary.Add(property, memberValue);
                }
                ++ordinal;
            }
            DbExpression left = (DbExpression)null;

            foreach (KeyValuePair <EdmProperty, PropagatorResult> keyValuePair in dictionary)
            {
                DbExpression equalityExpression = this.GenerateEqualityExpression(target, keyValuePair.Key, keyValuePair.Value);
                left = left != null ? (DbExpression)left.And(equalityExpression) : equalityExpression;
            }
            return(left);
        }
        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);
        }
Пример #3
0
        internal DbExpression AsCqt(DbExpression row, IEnumerable <Constant> constants, MemberPath outputMember, bool skipIsNotNull)
        {
            DbExpression cqt = null;

            AsCql(
                // trueLiteral action
                () => cqt = DbExpressionBuilder.True,
                // varIsNotNull action
                () => cqt = outputMember.AsCqt(row).IsNull().Not(),
                // varNotEqualsTo action
                (constant) =>
            {
                DbExpression notEqualsExpr = outputMember.AsCqt(row).NotEqual(constant.AsCqt(row, outputMember));
                if (cqt != null)
                {
                    cqt = cqt.And(notEqualsExpr);
                }
                else
                {
                    cqt = notEqualsExpr;
                }
            },
                constants, outputMember, skipIsNotNull);

            return(cqt);
        }
Пример #4
0
        public static DbExpression And(this DbExpression left, List <DbExpression> right)
        {
            for (int i = 0; i < right.Count; i++)
            {
                left = left.And(right[i]);
            }

            return(left);
        }
Пример #5
0
        /// <summary>
        ///     Determines predicate used to identify a row in a table.
        /// </summary>
        /// <remarks>
        ///     Columns are included in the list when:
        ///     <list>
        ///         <item>They are keys for the table</item>
        ///         <item>They are concurrency values</item>
        ///     </list>
        /// </remarks>
        /// <param name="target"> Expression binding representing the table containing the row </param>
        /// <param name="referenceRow"> Values for the row being located. </param>
        /// <param name="current"> Values being updated (may be null). </param>
        /// <param name="processor"> Context for the table containing the row. </param>
        /// <param name="rowMustBeTouched"> Output parameter indicating whether a row must be touched (whether it's being modified or not) because it contains a concurrency value </param>
        /// <returns> Column/value pairs. </returns>
        private DbExpression BuildPredicate(
            DbExpressionBinding target, PropagatorResult referenceRow, PropagatorResult current,
            TableChangeProcessor processor, ref bool rowMustBeTouched)
        {
            var whereClauses = new Dictionary <EdmProperty, PropagatorResult>();

            // add all concurrency tokens (note that keys are always concurrency tokens as well)
            var propertyOrdinal = 0;

            foreach (var member in processor.Table.ElementType.Properties)
            {
                // members and result values are ordinally aligned
                var expectedValue = referenceRow.GetMemberValue(propertyOrdinal);
                var newValue      = null == current ? null : current.GetMemberValue(propertyOrdinal);

                // check if the rowMustBeTouched value should be set to true (if it isn't already
                // true and we've come across a concurrency value)
                if (!rowMustBeTouched
                    &&
                    (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue) ||
                     HasFlag(newValue, PropagatorFlags.ConcurrencyValue)))
                {
                    rowMustBeTouched = true;
                }

                // determine if this is a concurrency value
                if (!whereClauses.ContainsKey(member)
                    &&                                                                           // don't add to the set clause twice
                    (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) ||
                     HasFlag(newValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) // tagged as concurrency value
                {
                    whereClauses.Add(member, expectedValue);
                }
                propertyOrdinal++;
            }

            // Build a binary AND expression tree from the clauses
            DbExpression predicate = null;

            foreach (var clause in whereClauses)
            {
                var clauseExpression = GenerateEqualityExpression(target, clause.Key, clause.Value);
                if (null == predicate)
                {
                    predicate = clauseExpression;
                }
                else
                {
                    predicate = predicate.And(clauseExpression);
                }
            }

            Debug.Assert(null != predicate, "some predicate term must exist");

            return(predicate);
        }
Пример #6
0
        /// <summary>
        /// Generates CQT representation of the slot.
        /// </summary>
        internal DbExpression AsCqt(DbExpression row)
        {
            DbExpression cqt = m_slotValue.AsCqt(row, m_outputMember);

            if (m_enforceNotNull)
            {
                cqt = cqt.And(cqt.IsNull().Not());
            }
            return(cqt);
        }
Пример #7
0
        internal DbExpression AsCqt(DbExpression row)
        {
            DbExpression left = this.m_slotValue.AsCqt(row, this.m_outputMember);

            if (this.m_enforceNotNull)
            {
                left = (DbExpression)left.And((DbExpression)left.IsNull().Not());
            }
            return(left);
        }
Пример #8
0
            internal DbExpression AsCqt(DbExpression leftRow, DbExpression rightRow)
            {
                DbExpression left = this.m_singleClauses[0].AsCqt(leftRow, rightRow);

                for (int index = 1; index < this.m_singleClauses.Count; ++index)
                {
                    left = (DbExpression)left.And(this.m_singleClauses[index].AsCqt(leftRow, rightRow));
                }
                return(left);
            }
Пример #9
0
            /// <summary>
            /// Generates CQT of the form "LeftSlot1 = RightSlot1 AND LeftSlot2 = RightSlot2 AND ...
            /// </summary>
            internal DbExpression AsCqt(DbExpression leftRow, DbExpression rightRow)
            {
                DbExpression cqt = m_singleClauses[0].AsCqt(leftRow, rightRow);

                for (int i = 1; i < m_singleClauses.Count; ++i)
                {
                    cqt = cqt.And(m_singleClauses[i].AsCqt(leftRow, rightRow));
                }
                return(cqt);
            }
Пример #10
0
        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);
        }
Пример #11
0
        public override DbExpression Visit(DbAndExpression expression)
        {
            DbExpression left  = this.VisitExpression(expression.Left);
            DbExpression right = this.VisitExpression(expression.Right);

            if (left != null && right != null)
            {
                return((DbExpression)left.And(right));
            }
            return(left ?? right);
        }
Пример #12
0
        static void AppendLimitCondition(DbSqlQueryExpression sqlQuery, int limitCount)
        {
            DbLessThanExpression lessThanExp = DbExpression.LessThan(OracleSemantics.DbMemberExpression_ROWNUM, DbExpression.Constant(limitCount + 1));

            DbExpression condition = lessThanExp;

            if (sqlQuery.Condition != null)
            {
                condition = DbExpression.And(sqlQuery.Condition, condition);
            }

            sqlQuery.Condition = condition;
        }
Пример #13
0
        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);
        }
Пример #14
0
        public static DbExpression MakeCondition(PairList <PrimitivePropertyDescriptor, object> propertyValuePairs, DbTable dbTable)
        {
            DbExpression conditionExp = null;

            foreach (var pair in propertyValuePairs)
            {
                PrimitivePropertyDescriptor propertyDescriptor = pair.Item1;
                object val = pair.Item2;

                DbExpression left     = new DbColumnAccessExpression(dbTable, propertyDescriptor.Column);
                DbExpression right    = DbExpression.Parameter(val, propertyDescriptor.PropertyType, propertyDescriptor.Column.DbType);
                DbExpression equalExp = new DbEqualExpression(left, right);
                conditionExp = conditionExp.And(equalExp);
            }

            return(conditionExp);
        }
Пример #15
0
        internal DbExpression AsCqt(
            DbExpression row,
            IEnumerable <Constant> constants,
            MemberPath outputMember,
            bool skipIsNotNull)
        {
            DbExpression cqt = (DbExpression)null;

            this.AsCql((Action)(() => cqt = (DbExpression)DbExpressionBuilder.True), (Action)(() => cqt = (DbExpression)outputMember.AsCqt(row).IsNull().Not()), (Action <Constant>)(constant =>
            {
                DbExpression right = (DbExpression)outputMember.AsCqt(row).NotEqual(constant.AsCqt(row, outputMember));
                if (cqt != null)
                {
                    cqt = (DbExpression)cqt.And(right);
                }
                else
                {
                    cqt = right;
                }
            }), constants, outputMember, skipIsNotNull);
            return(cqt);
        }
Пример #16
0
        static DbExpression MakeCondition(Dictionary <PropertyDescriptor, object> keyValueMap, DbTable dbTable)
        {
            DbExpression conditionExp = null;

            foreach (var kv in keyValueMap)
            {
                PropertyDescriptor keyPropertyDescriptor = kv.Key;
                object             keyVal = kv.Value;

                if (keyVal == null)
                {
                    throw new ArgumentException(string.Format("The primary key '{0}' could not be null.", keyPropertyDescriptor.Property.Name));
                }

                DbExpression left     = new DbColumnAccessExpression(dbTable, keyPropertyDescriptor.Column);
                DbExpression right    = DbExpression.Parameter(keyVal, keyPropertyDescriptor.PropertyType, keyPropertyDescriptor.Column.DbType);
                DbExpression equalExp = new DbEqualExpression(left, right);
                conditionExp = conditionExp == null ? equalExp : DbExpression.And(conditionExp, equalExp);
            }

            return(conditionExp);
        }
Пример #17
0
        /// <summary>
        /// Helper method creating the correct filter expression based on the supplied parameters
        /// </summary>
        private DbFilterExpression BuildFilterExpression(DbExpressionBinding binding, DbExpression predicate, string column)
        {
            _injectedDynamicFilter = true;

            var variableReference = binding.VariableType.Variable(binding.VariableName);
            // Create the property based on the variable in order to apply the equality
            var tenantProperty = variableReference.Property(column);
            // Create the parameter which is an object representation of a sql parameter.
            // We have to create a parameter and not perform a direct comparison with Equal function for example
            // as this logic is cached per query and called only once
            var tenantParameter = tenantProperty.Property.TypeUsage.Parameter(MultitenancyConstants.TenantIdFilterParameterName);
            // Apply the equality between property and parameter.
            DbExpression newPredicate = tenantProperty.Equal(tenantParameter);

            // If an existing predicate exists (normally when called from DbFilterExpression) execute a logical AND to get the result
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(binding.Filter(newPredicate));
        }
        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>
            /// Returns the update or query view for an Extent as a
            /// string.
            /// There are a series of steps that we go through for discovering a view for an extent.
            /// To start with we assume that we are working with Generated Views. To find out the
            /// generated view we go to the ObjectItemCollection and see if it is not-null. If the ObjectItemCollection
            /// is non-null, we get the view generation assemblies that it might have cached during the
            /// Object metadata discovery.If there are no view generation assemblies we switch to the
            /// runtime view generation strategy. If there are view generation assemblies, we get the list and
            /// go through them and see if there are any assemblies that are there from which we have not already loaded
            /// the views. We collect the views from assemblies that we have not already collected from earlier.
            /// If the ObjectItemCollection is null and we are in the view generation mode, that means that
            /// the query or update is issued from the Value layer and this is the first time view has been asked for.
            /// The compile time view gen for value layer queries will work for very simple scenarios.
            /// If the users wants to get the performance benefit, they should call MetadataWorkspace.LoadFromAssembly.
            /// At this point we go through the referenced assemblies of the entry assembly( this wont work for Asp.net
            /// or if the viewgen assembly was not referenced by the executing application).
            /// and try to see if there were any view gen assemblies. If there are, we collect the views for all extents.
            /// Once we have all the generated views gathered, we try to get the view for the extent passed in.
            /// If we find one we will return it. If we can't find one an exception will be thrown.
            /// If there were no view gen assemblies either in the ObjectItemCollection or in the list of referenced
            /// assemblies of calling assembly, we change the mode to runtime view generation and will continue to
            /// be in that mode for the rest of the lifetime of the mapping item collection.
            /// </summary>
            internal GeneratedView GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection)
            {
                //First check if we have collected a view from user-defined query views
                //Dont need to worry whether to generate Query view or update viw, because that is relative to the extent.
                GeneratedView view;

                if (TryGetUserDefinedQueryView(extent, out view))
                {
                    return(view);
                }

                //If this is a foreign key association, manufacture a view on the fly.
                if (extent.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                {
                    AssociationSet aSet = (AssociationSet)extent;
                    if (aSet.ElementType.IsForeignKey)
                    {
                        if (m_config.IsViewTracing)
                        {
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.FormatTraceLine("================= Generating FK Query View for: {0} =================", aSet.Name);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                        }

                        // Although we expose a collection of constraints in the API, there is only ever one constraint.
                        Debug.Assert(aSet.ElementType.ReferentialConstraints.Count == 1, "aSet.ElementType.ReferentialConstraints.Count == 1");
                        ReferentialConstraint rc = aSet.ElementType.ReferentialConstraints.Single();

                        EntitySet dependentSet = aSet.AssociationSetEnds[rc.ToRole.Name].EntitySet;
                        EntitySet principalSet = aSet.AssociationSetEnds[rc.FromRole.Name].EntitySet;

                        DbExpression qView = dependentSet.Scan();

                        // Introduce an OfType view if the dependent end is a subtype of the entity set
                        EntityType dependentType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)rc.ToRole);
                        EntityType principalType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)rc.FromRole);
                        if (dependentSet.ElementType.IsBaseTypeOf(dependentType))
                        {
                            qView = qView.OfType(TypeUsage.Create(dependentType));
                        }

                        if (rc.FromRole.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)
                        {
                            // Filter out instances with existing relationships.
                            qView = qView.Where(e =>
                            {
                                DbExpression filter = null;
                                foreach (EdmProperty fkProp in rc.ToProperties)
                                {
                                    DbExpression notIsNull = e.Property(fkProp).IsNull().Not();
                                    filter = null == filter ? notIsNull : filter.And(notIsNull);
                                }
                                return(filter);
                            });
                        }
                        qView = qView.Select(e =>
                        {
                            List <DbExpression> ends = new List <DbExpression>();
                            foreach (AssociationEndMember end in aSet.ElementType.AssociationEndMembers)
                            {
                                if (end.Name == rc.ToRole.Name)
                                {
                                    var keyValues = new List <KeyValuePair <string, DbExpression> >();
                                    foreach (EdmMember keyMember in dependentSet.ElementType.KeyMembers)
                                    {
                                        keyValues.Add(e.Property((EdmProperty)keyMember));
                                    }
                                    ends.Add(dependentSet.RefFromKey(DbExpressionBuilder.NewRow(keyValues), dependentType));
                                }
                                else
                                {
                                    // Manufacture a key using key values.
                                    var keyValues = new List <KeyValuePair <string, DbExpression> >();
                                    foreach (EdmMember keyMember in principalSet.ElementType.KeyMembers)
                                    {
                                        int offset = rc.FromProperties.IndexOf((EdmProperty)keyMember);
                                        keyValues.Add(e.Property(rc.ToProperties[offset]));
                                    }
                                    ends.Add(principalSet.RefFromKey(DbExpressionBuilder.NewRow(keyValues), principalType));
                                }
                            }
                            return(TypeUsage.Create(aSet.ElementType).New(ends));
                        });
                        return(GeneratedView.CreateGeneratedViewForFKAssociationSet(aSet, aSet.ElementType, new DbQueryCommandTree(workspace, DataSpace.SSpace, qView), storageMappingItemCollection, m_config));
                    }
                }

                // If no User-defined QV is found, call memoized View Generation procedure.
                Dictionary <EntitySetBase, GeneratedView> generatedViews = m_generatedViewsMemoizer.Evaluate(extent.EntityContainer);

                if (!generatedViews.TryGetValue(extent, out view))
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Views_For_Extent_Not_Generated(
                                                          (extent.EntityContainer.DataSpace == DataSpace.SSpace)?"Table":"EntitySet", extent.Name));
                }

                return(view);
            }
Пример #20
0
        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);
        }
        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);
        }
        // <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);
        }
Пример #23
0
        //  This is called for any navigation property reference so we can apply filters for those entities here.
        //  That includes any navigation properties referenced in functions (.Where() clauses) and also any
        //  child entities that are .Include()'d.
        public override DbExpression Visit(DbPropertyExpression expression)
        {
#if DEBUG_VISITS
            System.Diagnostics.Debug.Print("Visit(DbPropertyExpression): EdmType.Name={0}", expression.ResultType.ModelTypeUsage.EdmType.Name);
#endif
            var baseResult = base.Visit(expression);

            var basePropertyResult = baseResult as DbPropertyExpression;
            if (basePropertyResult == null)
            {
                return(baseResult);      //  base.Visit changed type!
            }
            var navProp = basePropertyResult.Property as NavigationProperty;
            if (navProp != null)
            {
                var targetEntityType = navProp.ToEndMember.GetEntityType();

                var containers = _ObjectContext.MetadataWorkspace.GetItems <EntityContainer>(DataSpace.CSpace).First();
                var filterList = FindFiltersForEntitySet(targetEntityType.MetadataProperties);

                if (filterList.Any())
                {
                    //  If the expression contains a collection (i.e. the child property is an IEnumerable), we can bind directly to it.
                    //  Otherwise, we have to create a DbScanExpression over the ResultType in order to bind.
                    if (baseResult.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
                    {
                        var binding             = DbExpressionBuilder.Bind(baseResult);
                        var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filterList, binding, null);
                        if (newFilterExpression != null)
                        {
                            //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                            return(newFilterExpression);
                        }
                    }
                    else if (baseResult.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                    {
                        if (DoesNotSupportElementMethod(_DbContext))
                        {
                            //  Oracle and MySQL do not support the "newFilterExpression.Element()" method that we need to call
                            //  at the end of this block.  Oracle *MAY* support it in a newer release but not sure
                            //  (see https://community.oracle.com/message/10168766#10168766).
                            //  But users may not have the option of upgrading their database so decided to try to support it.
                            //  If we find it is supported by newer versions, can detect those versions and allow the normal handling.
                            //  To apply any necessary filters to these entities, we're going to have to do it using SSpace.
                            //  These entities will be visited via the DbScan visit method so we will apply filters there.
                            //  If one of those filters then references a child property, the filter will fail.
                            return(baseResult);
                        }

                        DbExpression scanExpr;

                        var entitySet = containers.EntitySets.FirstOrDefault(e => e.ElementType.Name == baseResult.ResultType.EdmType.Name);
                        if (entitySet == null)
                        {
                            if (baseResult.ResultType.EdmType.BaseType == null)
                            {
                                throw new ApplicationException(string.Format("EntitySet not found for {0}", baseResult.ResultType.EdmType.Name));
                            }

                            //  Did not find the entity set for the property but it has a base type.
                            //  This means the entity set of the property is a derived class of a TPT base class.
                            //  Find the entity set of the parent and then map it to the type we need.
                            //  Then we can bind against that expression.
                            entitySet = containers.EntitySets.FirstOrDefault(e => e.ElementType.Name == baseResult.ResultType.EdmType.BaseType.Name);
                            if (entitySet == null)        //  hope we don't need to do this recursively...
                            {
                                throw new ApplicationException(string.Format("EntitySet not found for {0} or BaseType {1}", baseResult.ResultType.EdmType.Name, baseResult.ResultType.EdmType.BaseType.Name));
                            }

                            var parentScanExpr = DbExpressionBuilder.Scan(entitySet);
                            scanExpr = DbExpressionBuilder.OfType(parentScanExpr, baseResult.ResultType);
                        }
                        else
                        {
                            scanExpr = DbExpressionBuilder.Scan(entitySet);
                        }

                        var binding = DbExpressionBuilder.Bind(scanExpr);

                        //  Build the join conditions that are needed to join from the source object (basePropertyResult.Instance)
                        //  to the child object (the scan expression we just creating the binding for).
                        //  These conditions will be and'd with the filter conditions.
                        var associationType = navProp.RelationshipType as AssociationType;
                        if (associationType == null)
                        {
                            throw new ApplicationException(string.Format("Unable to find AssociationType on navigation property of single child property {0} in type {1}", navProp.Name, navProp.DeclaringType.FullName));
                        }
                        if (associationType.Constraint == null)
                        {
                            //  KNOWN_ISSUE:
                            //  If this happens, the model does not contain the foreign key (the "id" property).  EF will automatically generate
                            //  it based on naming rules when generating the SSpace/database models but does not expose the Constraint here in the
                            //  AssociationType.  In order for us to be able to generate the conditions correctly, those Foreign Keys need to be
                            //  specified on the model.  To fix/handle this, we would need to examine the SSpace Association Sets (which do have
                            //  these relations!!) to try to map that information back to CSpace to figure out the correct properties of the FK conditions.
                            //  or...the models just need to contain the necessary "ID" properties for the FK relations so that they are available here
                            //  (in CSpace) for us to generate the necessary join conditions.
                            throw new ApplicationException(string.Format("FK Constriant not found for association '{0}' - must directly specify foreign keys on model to be able to apply this filter", associationType.FullName));
                        }

                        //  Figure out if the "baseResults" are the from side or to side of the constraint so we can create the properties correctly
                        //  Note that this navigation property may be the same type as parent entity (so both association types
                        //  will be the same type).  In that case, we need to figure out which side of the association matches the
                        //  PKs of the main entity.
                        var  fromEdmType = ((AssociationEndMember)associationType.Constraint.FromRole).GetEntityType();
                        var  toEdmType   = ((AssociationEndMember)associationType.Constraint.ToRole).GetEntityType();
                        bool baseResultIsFromRole;
                        if (fromEdmType != toEdmType)
                        {
                            baseResultIsFromRole = (basePropertyResult.Instance.ResultType.EdmType == fromEdmType);
                        }
                        else
                        {
                            //  When same, basePropertyResult is the child property and binding is the main entity.
                            //  Fixes issue #85.
                            baseResultIsFromRole = false;
                        }

                        DbExpression joinCondition = null;
                        for (int i = 0; i < associationType.Constraint.FromProperties.Count; i++)
                        {
                            var prop1 = DbExpressionBuilder.Property(basePropertyResult.Instance, baseResultIsFromRole ? associationType.Constraint.FromProperties[i] : associationType.Constraint.ToProperties[i]);
                            var prop2 = DbExpressionBuilder.Property(binding.Variable, baseResultIsFromRole ? associationType.Constraint.ToProperties[i] : associationType.Constraint.FromProperties[i]);

                            var condition = prop1.Equal(prop2) as DbExpression;
                            joinCondition = (joinCondition == null) ? condition : joinCondition.And(condition);
                        }

                        //  Translate the filter predicate into a DbExpression bound to the Scan expression of the target entity set.
                        //  Those conditions are then and'd with the join conditions necessary to join the target table with the source table.
                        var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filterList, binding, joinCondition);
                        if (newFilterExpression != null)
                        {
                            //  Converts the collection results into a single row.  The expected output is a single item so EF will
                            //  then populate the results of that query into the property in the model.
                            //  The resulting SQL will be a normal "left outer join" just as it would normally be except that our
                            //  filter predicate conditions will be included with the normal join conditions.

                            //  MySQL needs this Limit() applied here or it throws an error saying:
                            //  Unable to cast object of type 'MySql.Data.Entity.SelectStatement' to type 'MySql.Data.Entity.LiteralFragment'.
                            //  But don't do that unless necessary because it produces extra "outer apply" sub queries in MS SQL.
                            //  This trick does not work for Oracle...
                            if (_DbContext.IsMySql())
                            {
                                return(newFilterExpression.Limit(DbConstantExpression.FromInt32(1)).Element());
                            }

                            return(newFilterExpression.Element());
                        }
                    }
                }
            }

            return(baseResult);
        }
Пример #24
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");
        }