Example #1
0
 /// <summary>
 /// Creates a new <see cref="DbNewInstanceExpression"/> that constructs a new row based on the columns
 /// contained in this Row instance.
 /// </summary>
 /// <returns>A new DbNewInstanceExpression that constructs a row with the same column names and DbExpression values as this Row instance</returns>
 /// <seealso cref="DbExpressionBuilder.NewRow"/>
 public DbNewInstanceExpression ToExpression()
 {
     return(DbExpressionBuilder.NewRow(this.arguments));
 }
Example #2
0
        public void CreateDbCommandDefinition_returns_wrapped_legacy_command_definition()
        {
            var commandDefinition =
                new LegacyDbProviderServicesWrapper(new Mock <SystemDataCommon.DbProviderServices>().Object)
                .CreateCommandDefinition(
                    new LegacyDbProviderManifestWrapper(LegacyProviderManifest),
                    new DbQueryCommandTree(CreateMetadataWorkspace(), DataSpace.SSpace, DbExpressionBuilder.Constant(42), false));

            Assert.NotNull(commandDefinition);
            Assert.IsType <LegacyDbCommandDefinitionWrapper>(commandDefinition);
        }
Example #3
0
 public override DbExpression Visit(DbParameterReferenceExpression expression)
 {
     // Inline parameters
     return(DbExpressionBuilder.Constant(_parameters[expression.ParameterName].Value));
 }
Example #4
0
        private Expression MapContainsExpression(MethodCallExpression node)
        {
            var expression = base.VisitMethodCall(node) as MethodCallExpression;

            //  For some reason, if the list is IEnumerable and not the List class, the
            //  list object (the ParameterExpression object) will be in Argument[0] and the param
            //  of the Contains() function will be in Argument[1].  And expression.object is null.
            //  In all other cases, the list object is in expression.Object and the Contains() param is Arguments[0]!

            DbExpression        argExpression    = null;
            ParameterExpression collectionObjExp = null;

            if ((expression.Arguments.Count > 1) && (expression.Object == null))
            {
                collectionObjExp = expression.Arguments[0] as ParameterExpression;
            }
            if (collectionObjExp != null)
            {
                argExpression = GetDbExpressionForExpression(expression.Arguments[1]);      //  IEnumerable
            }
            else
            {
                argExpression    = GetDbExpressionForExpression(expression.Arguments[0]);   //  List, IList, ICollection
                collectionObjExp = expression.Object as ParameterExpression;
            }

            DbExpression dbExpression;

            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, _DataSpace);

                var param = CreateParameter(paramName, paramType);
                dbExpression = DbExpressionBuilder.Equal(argExpression, 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 ?? "null"));
                }

                //  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() || !SupportsIn())
                {
                    //  Have parameters or the EF provider does not support the DbInExpression.  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 = DbExpressionBuilder.Equal(argExpression, paramReference);
                        if (dbExpression == null)
                        {
                            dbExpression = equalsExpression;
                        }
                        else
                        {
                            dbExpression = dbExpression.Or(equalsExpression);
                        }
                    }
                }
                else
                {
                    //  All values are constants so can use DbInExpression
                    dbExpression = DbExpressionBuilder.In(argExpression, constantExpressionList);
                }
            }

            MapExpressionToDbExpression(expression, dbExpression);
            return(expression);
        }
Example #5
0
        private Expression MapAnyOrAllExpression(MethodCallExpression node)
        {
            if (_DataSpace != DataSpace.CSpace)
            {
                throw new ApplicationException("Filters on child collections are only supported when using CSpace");
            }

            if ((node.Arguments == null) || (node.Arguments.Count > 2))
            {
                throw new ApplicationException("Any function call has more than 2 arguments");
            }

            //  Visit the first argument so that we can get the DbPropertyExpression which is the source of the method call.
            var sourceExpression     = Visit(node.Arguments[0]);
            var collectionExpression = GetDbExpressionForExpression(sourceExpression);

            //  Visit this DbExpression using the QueryVisitor in case it has it's own filters that need to be applied.
            var queryVisitor = new DynamicFilterQueryVisitorCSpace(_DbContext);

            collectionExpression = collectionExpression.Accept(queryVisitor);

            DbExpression dbExpression;

            if (node.Arguments.Count == 2)
            {
                //  The method call has a predicate that needs to be evaluated.  This must be done against the source
                //  argument - not the current binding.
                var binding = collectionExpression.Bind();

                //  Visit the lambda expression against this binding (which will evaluate all of the
                //  conditions in the expression against this binding and for this filter).
                var lambdaExpression = node.Arguments[1] as LambdaExpression;
                var visitor          = new LambdaToDbExpressionVisitor(_Filter, binding, _DbContext, _DataSpace);
                var subExpression    = visitor.Visit(lambdaExpression) as LambdaExpression;
                var subDbExpression  = visitor.GetDbExpressionForExpression(subExpression.Body);

                //  Create an "Any" or "All" DbExpression from the results
                if (node.Method.Name == "All")
                {
                    dbExpression = DbExpressionBuilder.All(binding, subDbExpression);
                }
                else
                {
                    dbExpression = DbExpressionBuilder.Any(binding, subDbExpression);
                }
            }
            else
            {
                //  This should not even be possible - linq/IEnumerable does not have such a method!
                if (node.Method.Name == "All")
                {
                    throw new ApplicationException("All() with no parameters is not supported");
                }

                //  No predicate so just create an Any DbExpression against the collection expression
                dbExpression = DbExpressionBuilder.Any(collectionExpression);
            }

            MapExpressionToDbExpression(node, dbExpression);
            return(node);
        }
        private DbExpression AddFkRelatedEntityRefs(DbExpression viewConstructor)
        {
            // If the extent being simplified is not a C-Space entity set, or if it has already
            // been processed by the simplifier, then keep the original expression by returning
            // null.
            //
            if (doNotProcess)
            {
                return(null);
            }

            if (extent.BuiltInTypeKind != BuiltInTypeKind.EntitySet
                ||
                extent.EntityContainer.DataSpace != DataSpace.CSpace)
            {
                doNotProcess = true;
                return(null);
            }

            // Get a reference to the entity set being simplified, and find all the foreign key
            // (foreign key) associations for which the association set references that entity set,
            // with either association end.
            //
            var targetSet = (EntitySet)extent;
            var relSets   =
                targetSet.EntityContainer.BaseEntitySets
                .Where(es => es.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                .Cast <AssociationSet>()
                .Where(
                    assocSet =>
                    assocSet.ElementType.IsForeignKey &&
                    assocSet.AssociationSetEnds.Any(se => se.EntitySet == targetSet)
                    )
                .ToList();

            // If no foreign key association sets that reference the entity set are present, then
            // no further processing is necessary, because FK-based related entity references cannot
            // be computed and added to the entities constructed for the entity set.
            if (relSets.Count == 0)
            {
                doNotProcess = true;
                return(null);
            }

            // For every relationship set that references this entity set, the relationship type and
            // foreign key constraint are used to determine if the entity set is the dependent set.
            // If it is the dependent set, then it is possible to augment the view definition with a
            // related entity ref that represents the navigation of the relationship set's relationship
            // from the dependent end (this entity set) to the the principal end (the entity set that
            // is referenced by the other association set end of the relationship set).
            //
            var principalSetsAndDependentTypes = new HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >();

            foreach (var relSet in relSets)
            {
                // Retrieve the single referential constraint from the foreign key association, and
                // use it to determine whether the association set end that represents the dependent
                // end of the association references this entity set.
                //
                var fkConstraint    = relSet.ElementType.ReferentialConstraints[0];
                var dependentSetEnd = relSet.AssociationSetEnds[fkConstraint.ToRole.Name];

                if (dependentSetEnd.EntitySet == targetSet)
                {
                    var requiredSourceNavType =
                        (EntityType)TypeHelpers.GetEdmType <RefType>(dependentSetEnd.CorrespondingAssociationEndMember.TypeUsage).ElementType;
                    var principalSetEnd = relSet.AssociationSetEnds[fkConstraint.FromRole.Name];

                    // Record the entity type that an element of this dependent entity set must have in order
                    // to be a valid navigation source for the relationship set's relationship, along with the
                    // association set end for the destination (principal) end of the navigation and the FK
                    // constraint that is associated with the relationship type. This information may be used
                    // later to construct a related entity ref for any entity constructor expression in the view
                    // that produces an entity of the required source type or a subtype.
                    //
                    principalSetsAndDependentTypes.Add(Tuple.Create(requiredSourceNavType, principalSetEnd, fkConstraint));
                }
            }

            // If no foreign key association sets that use the entity set as the dependent set are present,
            // then no further processing is possible, since FK-based related entity refs can only be added
            // to the view definition for navigations from the dependent end of the relationship to the principal.
            //
            if (principalSetsAndDependentTypes.Count == 0)
            {
                doNotProcess = true;
                return(null);
            }

            // This rule supports a view that is capped with a projection of the form
            // (input).Project(x => new Entity())
            // or
            // (input).Project(x => CASE WHEN (condition1) THEN new Entity1() ELSE WHEN (condition2) THEN new Entity2()... ELSE new EntityN())
            // where every new instance expression Entity1()...EntityN() constructs an entity of a type
            // that is compatible with the entity set's element type.
            // Here, the list of all DbNewInstanceExpressions contained in the projection is remembered,
            // along with any CASE statement conditions, if present. These expressions will be updated
            // if necessary and used to build a new capping projection if any of the entity constructors
            // are augmented with FK-based related entity references.
            //
            var entityProject = (DbProjectExpression)viewConstructor;
            var constructors  = new List <DbNewInstanceExpression>();
            List <DbExpression> conditions = null;

            if (entityProject.Projection.ExpressionKind
                == DbExpressionKind.Case)
            {
                // If the projection is a DbCaseExpression, then every result must be a DbNewInstanceExpression
                var discriminatedConstructor = (DbCaseExpression)entityProject.Projection;
                conditions = new List <DbExpression>(discriminatedConstructor.When.Count);
                for (var idx = 0; idx < discriminatedConstructor.When.Count; idx++)
                {
                    conditions.Add(discriminatedConstructor.When[idx]);
                    constructors.Add((DbNewInstanceExpression)discriminatedConstructor.Then[idx]);
                }
                constructors.Add((DbNewInstanceExpression)discriminatedConstructor.Else);
            }
            else
            {
                // Otherwise, the projection must be a single DbNewInstanceExpression
                constructors.Add((DbNewInstanceExpression)entityProject.Projection);
            }

            var rebuildView = false;

            for (var idx = 0; idx < constructors.Count; idx++)
            {
                var entityConstructor     = constructors[idx];
                var constructedEntityType = TypeHelpers.GetEdmType <EntityType>(entityConstructor.ResultType);

                var relatedRefs =
                    principalSetsAndDependentTypes
                    .Where(psdt => constructedEntityType == psdt.Item1 || constructedEntityType.IsSubtypeOf(psdt.Item1))
                    .Select(
                        psdt => RelatedEntityRefFromAssociationSetEnd(constructedEntityType, entityConstructor, psdt.Item2, psdt.Item3))
                    .ToList();

                if (relatedRefs.Count > 0)
                {
                    if (entityConstructor.HasRelatedEntityReferences)
                    {
                        relatedRefs = entityConstructor.RelatedEntityReferences.Concat(relatedRefs).ToList();
                    }

                    entityConstructor = DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(
                        constructedEntityType, entityConstructor.Arguments, relatedRefs);
                    constructors[idx] = entityConstructor;
                    rebuildView       = true;
                }
            }

            // Default to returning null to indicate that this rule did not produce a modified expression
            //
            DbExpression result = null;

            if (rebuildView)
            {
                // rebuildView is true, so entity constructing DbNewInstanceExpression(s) were encountered
                // and updated with additional related entity refs. The DbProjectExpression that caps the
                // view definition therefore needs to be rebuilt and returned as the result of this rule.
                //
                if (conditions != null)
                {
                    // The original view definition projection was a DbCaseExpression.
                    // The new expression is also a DbCaseExpression that uses the conditions from the
                    // original expression together with the updated result expressions to produce the
                    // new capping projection.
                    //
                    var whens = new List <DbExpression>(conditions.Count);
                    var thens = new List <DbExpression>(conditions.Count);
                    for (var idx = 0; idx < conditions.Count; idx++)
                    {
                        whens.Add(conditions[idx]);
                        thens.Add(constructors[idx]);
                    }

                    result = entityProject.Input.Project(DbExpressionBuilder.Case(whens, thens, constructors[conditions.Count]));
                }
                else
                {
                    // Otherwise, the capping projection consists entirely of the updated DbNewInstanceExpression.
                    //
                    result = entityProject.Input.Project(constructors[0]);
                }
            }

            // Regardless of whether or not the view was updated, this rule should not be applied again during rule processing
            doNotProcess = true;
            return(result);
        }
Example #7
0
        protected override Expression VisitConstant(ConstantExpression node)
        {
#if (DEBUG_VISITS)
            System.Diagnostics.Debug.Print("VisitConstant: {0}", node);
#endif

            var expression = base.VisitConstant(node);

            var type = node.Type;
            if (IsNullableType(type))
            {
                var genericArgs = type.GetGenericArguments();
                if ((genericArgs != null) && (genericArgs.Length == 1))
                {
                    type = genericArgs[0];
                }
            }

            if (type == typeof(byte[]))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromBinary((byte[])node.Value));
            }
            else if (type == typeof(bool))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromBoolean((bool?)node.Value));
            }
            else if (type == typeof(byte))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromByte((byte?)node.Value));
            }
            else if (type == typeof(DateTime))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromDateTime((DateTime?)node.Value));
            }
            else if (type == typeof(DateTimeOffset))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromDateTimeOffset((DateTimeOffset?)node.Value));
            }
            else if (type == typeof(decimal))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromDecimal((decimal?)node.Value));
            }
            else if (type == typeof(double))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromDouble((double?)node.Value));
            }
            else if (type == typeof(Guid))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromGuid((Guid?)node.Value));
            }
            else if (type == typeof(Int16))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromInt16((Int16?)node.Value));
            }
            else if (type == typeof(Int32))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromInt32((Int32?)node.Value));
            }
            else if (type.IsEnum)
            {
                if (_DataSpace == DataSpace.CSpace)
                {
                    var typeUsage = TypeUsageForPrimitiveType(node.Type);
                    MapExpressionToDbExpression(expression, DbExpressionBuilder.Constant(typeUsage, node.Value));
                }
                else
                {
                    MapExpressionToDbExpression(expression, DbConstantExpression.FromInt32((Int32)node.Value));
                }
            }
            else if (type == typeof(Int64))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromInt64((Int64?)node.Value));
            }
            else if (type == typeof(float))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromSingle((float?)node.Value));
            }
            else if (type == typeof(string))
            {
                MapExpressionToDbExpression(expression, DbConstantExpression.FromString((string)node.Value));
            }
            else
            {
                throw new NotImplementedException(string.Format("Unhandled Type of {0} for Constant value {1} in LambdaToDbExpressionVisitor.VisitConstant", node.Type.Name, node.Value ?? "null"));
            }

            return(expression);
        }
Example #8
0
        private IEnumerable <DbModificationClause> BuildSetClauses(
            DbExpressionBinding target,
            PropagatorResult row,
            PropagatorResult originalRow,
            TableChangeProcessor processor,
            bool insertMode,
            out Dictionary <int, string> outputIdentifiers,
            out DbExpression returning,
            ref bool rowMustBeTouched)
        {
            Dictionary <EdmProperty, PropagatorResult>  dictionary       = new Dictionary <EdmProperty, PropagatorResult>();
            List <KeyValuePair <string, DbExpression> > keyValuePairList = new List <KeyValuePair <string, DbExpression> >();

            outputIdentifiers = new Dictionary <int, string>();
            PropagatorFlags propagatorFlags1 = insertMode ? PropagatorFlags.NoFlags : PropagatorFlags.Preserve | PropagatorFlags.Unknown;

            for (int index1 = 0; index1 < processor.Table.ElementType.Properties.Count; ++index1)
            {
                EdmProperty      property = processor.Table.ElementType.Properties[index1];
                PropagatorResult result   = row.GetMemberValue(index1);
                if (-1 != result.Identifier)
                {
                    result = result.ReplicateResultWithNewValue(this.m_translator.KeyManager.GetPrincipalValue(result));
                }
                bool flag1 = false;
                bool flag2 = false;
                for (int index2 = 0; index2 < processor.KeyOrdinals.Length; ++index2)
                {
                    if (processor.KeyOrdinals[index2] == index1)
                    {
                        flag2 = true;
                        break;
                    }
                }
                PropagatorFlags propagatorFlags2 = PropagatorFlags.NoFlags;
                if (!insertMode && flag2)
                {
                    flag1 = true;
                }
                else
                {
                    propagatorFlags2 |= result.PropagatorFlags;
                }
                StoreGeneratedPattern generatedPattern = MetadataHelper.GetStoreGeneratedPattern((EdmMember)property);
                bool flag3 = generatedPattern == StoreGeneratedPattern.Computed || insertMode && generatedPattern == StoreGeneratedPattern.Identity;
                if (flag3)
                {
                    DbPropertyExpression propertyExpression = target.Variable.Property(property);
                    keyValuePairList.Add(new KeyValuePair <string, DbExpression>(property.Name, (DbExpression)propertyExpression));
                    int identifier = result.Identifier;
                    if (-1 != identifier)
                    {
                        if (this.m_translator.KeyManager.HasPrincipals(identifier))
                        {
                            throw new InvalidOperationException(Strings.Update_GeneratedDependent((object)property.Name));
                        }
                        outputIdentifiers.Add(identifier, property.Name);
                        if (generatedPattern != StoreGeneratedPattern.Identity && processor.IsKeyProperty(index1))
                        {
                            throw new NotSupportedException(Strings.Update_NotSupportedComputedKeyColumn((object)"StoreGeneratedPattern", (object)"Computed", (object)"Identity", (object)property.Name, (object)property.DeclaringType.FullName));
                        }
                    }
                }
                if ((propagatorFlags2 & propagatorFlags1) != PropagatorFlags.NoFlags)
                {
                    flag1 = true;
                }
                else if (flag3)
                {
                    flag1            = true;
                    rowMustBeTouched = true;
                }
                if (!flag1 && !insertMode && generatedPattern == StoreGeneratedPattern.Identity)
                {
                    PropagatorResult memberValue = originalRow.GetMemberValue(index1);
                    if (!ByValueEqualityComparer.Default.Equals(memberValue.GetSimpleValue(), result.GetSimpleValue()))
                    {
                        throw new InvalidOperationException(Strings.Update_ModifyingIdentityColumn((object)"Identity", (object)property.Name, (object)property.DeclaringType.FullName));
                    }
                    flag1 = true;
                }
                if (!flag1)
                {
                    dictionary.Add(property, result);
                }
            }
            returning = 0 >= keyValuePairList.Count ? (DbExpression)null : (DbExpression)DbExpressionBuilder.NewRow((IEnumerable <KeyValuePair <string, DbExpression> >)keyValuePairList);
            List <DbModificationClause> modificationClauseList = new List <DbModificationClause>(dictionary.Count);

            foreach (KeyValuePair <EdmProperty, PropagatorResult> keyValuePair in dictionary)
            {
                EdmProperty key = keyValuePair.Key;
                modificationClauseList.Add((DbModificationClause) new DbSetClause(UpdateCompiler.GeneratePropertyExpression(target, keyValuePair.Key), this.GenerateValueExpression(keyValuePair.Key, keyValuePair.Value)));
            }
            return((IEnumerable <DbModificationClause>)modificationClauseList);
        }
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(string entityName, IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    var edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(filter.ColumnName))).FirstOrDefault();
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName));

                    dbExpression = DbExpressionBuilder.Equal(columnProperty, param);
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _ObjectContext);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                //  the filter has been disabled.
                var boolPrimitiveType = _ObjectContext.MetadataWorkspace
                                        .GetPrimitiveTypes(DataSpace.CSpace)
                                        .Where(p => p.ClrEquivalentType == typeof(bool))
                                        .Single();
                var isDisabledParam = DbExpressionBuilder.Parameter(TypeUsage.Create(boolPrimitiveType, new List <Facet>()), filter.CreateFilterDisabledParameterName());
                conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }
Example #10
0
        public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
        {
            if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
            {
                var insertCommand = interceptionContext.Result as DbInsertCommandTree;
                if (insertCommand != null)
                {
                    List <DbModificationClause> finalSetClauses =
                        new List <DbModificationClause>(
                            (IEnumerable <DbModificationClause>)insertCommand.SetClauses.Select(
                                a =>
                    {
                        var dbSetClause = a as DbSetClause;
                        if (dbSetClause != null)
                        {
                            var dbPropertyExpression = dbSetClause.Property as DbPropertyExpression;

                            if (dbPropertyExpression != null)
                            {
                                var edmProperty = dbPropertyExpression.Property as EdmProperty;
                                if (edmProperty != null && edmProperty.MaxLength != null &&
                                    _typesToTrim.Contains(edmProperty.TypeName))
                                {
                                    var dbConstantExpression = dbSetClause.Value as DbConstantExpression;
                                    if (dbConstantExpression != null && dbConstantExpression.Value != null)
                                    {
                                        var value = dbConstantExpression.Value.ToString();
                                        if (!string.IsNullOrEmpty(value) &&
                                            value.Length > (int)edmProperty.MaxLength)
                                        {
                                            return(DbExpressionBuilder.SetClause(
                                                       DbExpressionBuilder.Property(
                                                           DbExpressionBuilder.Variable(
                                                               insertCommand.Target.VariableType,
                                                               insertCommand.Target.VariableName),
                                                           dbPropertyExpression.Property.Name),
                                                       EdmFunctions.Trim(
                                                           dbConstantExpression.Value.ToString()
                                                           .Substring(0, (int)edmProperty.MaxLength))));
                                        }
                                    }
                                }
                            }
                        }

                        return(a);
                    }));

                    var newInsertCommand = new DbInsertCommandTree(
                        insertCommand.MetadataWorkspace,
                        insertCommand.DataSpace,
                        insertCommand.Target,
                        new ReadOnlyCollection <DbModificationClause>(finalSetClauses),
                        insertCommand.Returning);

                    interceptionContext.Result = newInsertCommand;
                }
            }

            var updateCommand = interceptionContext.Result as DbUpdateCommandTree;

            if (updateCommand != null)
            {
                List <DbModificationClause> finalSetClauses =
                    new List <DbModificationClause>(
                        (IEnumerable <DbModificationClause>)updateCommand.SetClauses.Select(
                            a =>
                {
                    var dbSetClause = a as DbSetClause;
                    if (dbSetClause != null)
                    {
                        var dbPropertyExpression = dbSetClause.Property as DbPropertyExpression;

                        if (dbPropertyExpression != null)
                        {
                            var edmProperty = dbPropertyExpression.Property as EdmProperty;
                            if (edmProperty != null && edmProperty.MaxLength != null &&
                                _typesToTrim.Contains(edmProperty.TypeName))
                            {
                                var dbConstantExpression = dbSetClause.Value as DbConstantExpression;
                                if (dbConstantExpression != null && dbConstantExpression.Value != null)
                                {
                                    var value = dbConstantExpression.Value.ToString();
                                    if (!string.IsNullOrEmpty(value) &&
                                        value.Length > (int)edmProperty.MaxLength)
                                    {
                                        return(DbExpressionBuilder.SetClause(
                                                   DbExpressionBuilder.Property(
                                                       DbExpressionBuilder.Variable(
                                                           updateCommand.Target.VariableType,
                                                           updateCommand.Target.VariableName),
                                                       dbPropertyExpression.Property.Name),
                                                   EdmFunctions.Trim(
                                                       dbConstantExpression.Value.ToString()
                                                       .Substring(0, (int)edmProperty.MaxLength))));
                                    }
                                }
                            }
                        }
                    }

                    return(a);
                }));

                var newInsertCommand = new DbUpdateCommandTree(
                    updateCommand.MetadataWorkspace,
                    updateCommand.DataSpace,
                    updateCommand.Target,
                    updateCommand.Predicate,
                    new ReadOnlyCollection <DbModificationClause>(finalSetClauses),
                    updateCommand.Returning);

                interceptionContext.Result = newInsertCommand;
            }
        }
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(string entityName, IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    var edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(filter.ColumnName))).FirstOrDefault();
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName, DataSpace.SSpace));

                    //  When using SSpace, need some special handling for an Oracle Boolean property.
                    //  Not necessary when using CSpace since the translation into the Oracle types has not happened yet.
                    if ((columnProperty.ResultType.EdmType.FullName == "Edm.Boolean") &&
                        param.ResultType.EdmType.FullName.StartsWith("Oracle", StringComparison.CurrentCultureIgnoreCase) && (param.ResultType.EdmType.Name == "number"))       //  Don't trust Oracle's type name to stay the same...
                    {
                        //  Special handling needed for columnProperty boolean.  For some reason, the Oracle EF driver does not correctly
                        //  set the ResultType to a number(1) in columnProperty like it does in columnProperty.Property.TypeUsage.  That
                        //  results in us trying to do a comparison of a Boolean to a number(1) which causes DbExpressionBuilder.Equal
                        //  to throw an exception.  To get this to process correctly, we need to do a cast on the columnProperty to
                        //  "number(1)" so that it matches the param.ResultType.  And that results in the sql sent to Oracle converting
                        //  the column to the type that it already is...
                        dbExpression = DbExpressionBuilder.Equal(DbExpressionBuilder.CastTo(columnProperty, param.ResultType), param);
                    }
                    else
                    {
                        dbExpression = DbExpressionBuilder.Equal(columnProperty, param);
                    }
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _DbContext, DataSpace.SSpace);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                if (DynamicFilterExtensions.AreFilterDisabledConditionsAllowed(filter.FilterName))
                {
                    //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                    //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                    //  the filter has been disabled.
                    var boolPrimitiveType = LambdaToDbExpressionVisitor.TypeUsageForPrimitiveType(typeof(bool?), _ObjectContext, DataSpace.SSpace);
                    var isDisabledParam   = boolPrimitiveType.Parameter(filter.CreateFilterDisabledParameterName(DataSpace.SSpace));

                    conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
                }
                else
                {
                    conditionList.Add(dbExpression);
                }
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }
Example #12
0
 public override DbExpression Visit(DbParameterReferenceExpression expression)
 {
     return((DbExpression)DbExpressionBuilder.Constant(this._parameters[expression.ParameterName].Value));
 }
Example #13
0
        /// <summary>
        /// Visit a Member Expression.  Creates a mapping of the MemberExpression to a DbPropertyExpression
        /// which is a reference to the table/column name that matches the MemberExpression.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMember(MemberExpression node)
        {
#if (DEBUGPRINT)
            System.Diagnostics.Debug.Print("VisitMember: {0}, expression.NodeType={1}, Member={2}", node, node.Expression.NodeType, node.Member);
#endif

            var expression = base.VisitMember(node) as MemberExpression;

            if ((expression.Expression.NodeType == ExpressionType.Parameter) && (expression.Expression.Type.IsClass || expression.Expression.Type.IsInterface))
            {
                //  expression is a reference to a class/interface property.  Need to map it to a sql parameter or look up
                //  the existing parameter.
                //  The class/interface is defined by expression.Expression while the property is in expression.Member.
                string propertyName;
                if (IsNullableType(expression.Member.ReflectedType))
                {
                    var subExpression = expression.Expression as MemberExpression;
                    propertyName = subExpression.Member.Name;
                }
                else
                {
                    propertyName = expression.Member.Name;
                }

                //  TODO: To support different class/interfaces, can we figure out the correct binding from what's in expression.Expression?
                var edmType = _Binding.VariableType.EdmType as EntityType;

                DbPropertyExpression propertyExpression;
                if (!_Properties.TryGetValue(propertyName, out propertyExpression))
                {
                    //  Not created yet

                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    var edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(propertyName))).FirstOrDefault();
                    if (edmProp == null)
                    {
                        //  Accessing properties outside the main entity is not supported and will cause this exception.
                        throw new ApplicationException(string.Format("Property {0} not found in Entity Type {1}", propertyName, expression.Expression.Type.Name));
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    propertyExpression = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(_Binding.VariableType, _Binding.VariableName), edmProp.Name);
                    _Properties.Add(propertyName, propertyExpression);

#if (DEBUGPRINT)
                    System.Diagnostics.Debug.Print("Created new property expression for {0}", propertyName);
#endif
                }

                //  Nothing else to do here
                MapExpressionToDbExpression(expression, propertyExpression);
                return(expression);
            }

            //  We are accessing a member property such that expression.Expression is the object and expression.Member is the property.
            //  And the property is one that requires special handling.  Regular class properties are all handled up above.
            var objectExpression = GetDbExpressionForExpression(expression.Expression);

            DbExpression dbExpression;
            switch (expression.Member.Name)
            {
            case "HasValue":
                //  Map HasValue to !IsNull
                dbExpression = DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(objectExpression));
                break;

            case "Value":
                //  This is a nullable Value accessor so just map to the object itself and it will be mapped for us
                dbExpression = objectExpression;
                break;

            default:
                throw new ApplicationException(string.Format("Unhandled property accessor in expression: {0}", expression));
            }

            MapExpressionToDbExpression(expression, dbExpression);
            return(expression);
        }
 public override DbExpression Visit(DbScanExpression expression)
 {
     // here we go!
     return(DbExpressionBuilder.Limit(expression, 128));
 }
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                _AppliedFilters.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    var edmProp = edmType.Properties.FirstOrDefault(p => p.Name == filter.ColumnName);
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName, DataSpace.CSpace));

                    dbExpression = DbExpressionBuilder.Equal(columnProperty, param);

                    //  When using SSpace, need some special handling for an Oracle Boolean property.
                    //  Not necessary when using CSpace since the translation into the Oracle types has not happened yet.
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _DbContext, DataSpace.CSpace);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                if (DynamicFilterExtensions.AreFilterDisabledConditionsAllowed(filter.FilterName))
                {
                    //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                    //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                    //  the filter has been disabled.
                    var boolPrimitiveType = LambdaToDbExpressionVisitor.TypeUsageForPrimitiveType(typeof(bool?), _ObjectContext, DataSpace.CSpace);
                    var isDisabledParam   = boolPrimitiveType.Parameter(filter.CreateFilterDisabledParameterName(DataSpace.CSpace));

                    conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
                }
                else
                {
                    conditionList.Add(dbExpression);
                }
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }
Example #16
0
        private DbExpression RewriteEntity(DbExpression expression, EntityType entityType)
        {
            // If the expression is an Entity constructor, spanning will not produce any useful results
            // (null for an Entity/Ref navigation property, or an empty collection for a Collection
            // of Entity/Ref navigation property) since a Ref produced from the constructed Entity
            // will not indicate an Entity set, and therefore no Ref created against any Entity set
            // in the container can possibly be a match for it.
            if (DbExpressionKind.NewInstance
                == expression.ExpressionKind)
            {
                return(expression);
            }

            // Save the span count for later use.
            _spanCount++;
            var thisSpan = _spanCount;

            var tracking = CreateEntitySpanTrackingInfo(expression, entityType);

            // If relationship span is required then attempt to span any appropriate relationship ends.
            List <KeyValuePair <AssociationEndMember, AssociationEndMember> > relationshipSpans = null;

            relationshipSpans = GetRelationshipSpanEnds(entityType);
            // Is the Entity type of this expression valid as the source of at least one relationship span?
            if (relationshipSpans != null)
            {
                // If the span tracking information was not initialized by CreateEntitySpanTrackingInfo,
                // then do so now as relationship span rewrites need to be tracked.
                if (null == tracking.ColumnDefinitions)
                {
                    tracking = InitializeTrackingInfo(false);
                }

                // Track column index to span information, starting at the current column count (which could be zero) plus 1.
                // 1 is added because the column containing the root entity will be added later to provide column zero.
                var idx = tracking.ColumnDefinitions.Count + 1;
                // For all applicable relationship spans that were identified...
                foreach (var relSpan in relationshipSpans)
                {
                    // If the specified association end member was already full-spanned then the full entity
                    // will be returned in the query and there is no need to relationship-span this end to produce
                    // another result column that contains the Entity key of the full entity.
                    // Hence the relationship span is only added if there are no full-span columns or the full-span
                    // columns do not indicate that they include the target association end member of this relationship span.
                    if (null == tracking.FullSpannedEnds
                        ||
                        !tracking.FullSpannedEnds.ContainsKey(relSpan.Value))
                    {
                        // If the source Ref is already available, because the currently spanned Entity is
                        // the result of a Relationship Navigation operation from that Ref, then use the source
                        // Ref directly rather than introducing a new Navigation operation.
                        DbExpression columnDef = null;
                        if (!TryGetNavigationSource(relSpan.Value, out columnDef))
                        {
                            // Add a new column defined by the navigation required to reach the targeted association end
                            // and update the column -> association end map to include an entry for this new column.
                            DbExpression navSource = expression.GetEntityRef();
                            columnDef = navSource.NavigateAllowingAllRelationshipsInSameTypeHierarchy(relSpan.Key, relSpan.Value);
                        }

                        tracking.ColumnDefinitions.Add(
                            new KeyValuePair <string, DbExpression>(
                                tracking.ColumnNames.Next(),
                                columnDef
                                )
                            );

                        tracking.SpannedColumns[idx] = relSpan.Value;

                        // Increment the tracked column count
                        idx++;
                    }
                }
            }

            // If no spanned columns have been added then simply return the original expression
            if (null == tracking.ColumnDefinitions)
            {
                _spanCount--;
                return(expression);
            }

            // Add the original entity-producing expression as the first (root) span column.
            tracking.ColumnDefinitions.Insert(
                0,
                new KeyValuePair <string, DbExpression>(
                    string.Format(CultureInfo.InvariantCulture, "Span{0}_SpanRoot", thisSpan),
                    expression
                    )
                );

            // Create the span row-producing NewInstanceExpression from which the span RowType can be retrieved.
            DbExpression spannedExpression = DbExpressionBuilder.NewRow(tracking.ColumnDefinitions);

            // Update the rowtype -> spaninfo map for the newly created row type instance.
            var spanRowType = (RowType)spannedExpression.ResultType.EdmType;

            AddSpanMap(spanRowType, tracking.SpannedColumns);

            // Return the rewritten expression
            return(spannedExpression);
        }
Example #17
0
        private static DbExpression SimplifyNestedTphDiscriminator(DbExpression expression)
        {
            var entityProjection    = (DbProjectExpression)expression;
            var booleanColumnFilter = (DbFilterExpression)entityProjection.Input.Expression;
            var rowProjection       = (DbProjectExpression)booleanColumnFilter.Input.Expression;
            var discriminatorFilter = (DbFilterExpression)rowProjection.Input.Expression;

            var predicates         = FlattenOr(booleanColumnFilter.Predicate).ToList();
            var propertyPredicates =
                predicates.OfType <DbPropertyExpression>()
                .Where(
                    px => px.Instance.ExpressionKind == DbExpressionKind.VariableReference &&
                    ((DbVariableReferenceExpression)px.Instance).VariableName == booleanColumnFilter.Input.VariableName)
                .ToList();

            if (predicates.Count
                != propertyPredicates.Count)
            {
                return(null);
            }

            var predicateColumnNames = propertyPredicates.Select(px => px.Property.Name).ToList();

            var discriminatorPredicates = new Dictionary <object, DbComparisonExpression>();

            if (!TypeSemantics.IsEntityType(discriminatorFilter.Input.VariableType)
                ||
                !TryMatchDiscriminatorPredicate(discriminatorFilter, (compEx, discValue) => discriminatorPredicates.Add(discValue, compEx)))
            {
                return(null);
            }

            var discriminatorProp    = (EdmProperty)((DbPropertyExpression)(discriminatorPredicates.First().Value).Left).Property;
            var rowConstructor       = (DbNewInstanceExpression)rowProjection.Projection;
            var resultRow            = TypeHelpers.GetEdmType <RowType>(rowConstructor.ResultType);
            var inputPredicateMap    = new Dictionary <string, DbComparisonExpression>();
            var selectorPredicateMap = new Dictionary <string, DbComparisonExpression>();
            var columnValues         = new Dictionary <string, DbExpression>(rowConstructor.Arguments.Count);

            for (var idx = 0; idx < rowConstructor.Arguments.Count; idx++)
            {
                var propName  = resultRow.Properties[idx].Name;
                var columnVal = rowConstructor.Arguments[idx];
                if (predicateColumnNames.Contains(propName))
                {
                    if (columnVal.ExpressionKind
                        != DbExpressionKind.Case)
                    {
                        return(null);
                    }
                    var casePredicate = (DbCaseExpression)columnVal;
                    if (casePredicate.When.Count != 1
                        ||
                        !TypeSemantics.IsBooleanType(casePredicate.Then[0].ResultType) ||
                        !TypeSemantics.IsBooleanType(casePredicate.Else.ResultType)
                        ||
                        casePredicate.Then[0].ExpressionKind != DbExpressionKind.Constant ||
                        casePredicate.Else.ExpressionKind != DbExpressionKind.Constant
                        ||
                        (bool)((DbConstantExpression)casePredicate.Then[0]).Value != true ||
                        (bool)((DbConstantExpression)casePredicate.Else).Value)
                    {
                        return(null);
                    }

                    DbPropertyExpression comparedProp;
                    object constValue;
                    if (
                        !TryMatchPropertyEqualsValue(
                            casePredicate.When[0], rowProjection.Input.VariableName, out comparedProp, out constValue)
                        ||
                        comparedProp.Property != discriminatorProp
                        ||
                        !discriminatorPredicates.ContainsKey(constValue))
                    {
                        return(null);
                    }

                    inputPredicateMap.Add(propName, discriminatorPredicates[constValue]);
                    selectorPredicateMap.Add(propName, (DbComparisonExpression)casePredicate.When[0]);
                }
                else
                {
                    columnValues.Add(propName, columnVal);
                }
            }

            // Build a new discriminator-based filter that only includes the same rows allowed by the higher '_from0' column-based filter
            var newDiscriminatorPredicate = Helpers.BuildBalancedTreeInPlace(
                new List <DbExpression>(inputPredicateMap.Values), (left, right) => left.Or(right));

            discriminatorFilter = discriminatorFilter.Input.Filter(newDiscriminatorPredicate);

            var entitySelector = (DbCaseExpression)entityProjection.Projection;
            var newWhens       = new List <DbExpression>(entitySelector.When.Count);
            var newThens       = new List <DbExpression>(entitySelector.Then.Count);

            for (var idx = 0; idx < entitySelector.When.Count; idx++)
            {
                var propWhen   = (DbPropertyExpression)entitySelector.When[idx];
                var entityThen = (DbNewInstanceExpression)entitySelector.Then[idx];

                DbComparisonExpression discriminatorWhen;
                if (!selectorPredicateMap.TryGetValue(propWhen.Property.Name, out discriminatorWhen))
                {
                    return(null);
                }
                newWhens.Add(discriminatorWhen);

                var inputBoundEntityConstructor = ValueSubstituter.Substitute(entityThen, entityProjection.Input.VariableName, columnValues);
                newThens.Add(inputBoundEntityConstructor);
            }

            var newElse           = ValueSubstituter.Substitute(entitySelector.Else, entityProjection.Input.VariableName, columnValues);
            var newEntitySelector = DbExpressionBuilder.Case(newWhens, newThens, newElse);

            DbExpression result = discriminatorFilter.BindAs(rowProjection.Input.VariableName).Project(newEntitySelector);

            return(result);
        }
Example #18
0
        private DbExpression RewriteRow(DbExpression expression, RowType rowType)
        {
            var lambdaExpression = expression as DbLambdaExpression;
            DbNewInstanceExpression newRow;

            if (lambdaExpression != null)
            {
                // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions
                // created by users, because user-created expressions cannot be used for querying in O-space.
                // If that were to change, pushing span beyond a LambdaExpression could cause variable name
                // collisions between the variable names used in the Lambda and the names generated by the
                // RelationshipNavigationVisitor.
                newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression;
            }
            else
            {
                newRow = expression as DbNewInstanceExpression;
            }

            Dictionary <int, DbExpression> unmodifiedColumns = null;
            Dictionary <int, DbExpression> spannedColumns    = null;

            for (var idx = 0; idx < rowType.Properties.Count; idx++)
            {
                // Retrieve the property that represents the current column
                var columnProp = rowType.Properties[idx];

                // Construct an expression that defines the current column.
                DbExpression columnExpr = null;
                if (newRow != null)
                {
                    // For a row-constructing NewInstance expression, the corresponding argument can simply be used
                    columnExpr = newRow.Arguments[idx];
                }
                else
                {
                    // For all other expressions the property corresponding to the column name must be retrieved
                    // from the row-typed expression
                    columnExpr = expression.Property(columnProp.Name);
                }

                var spannedColumn = Rewrite(columnExpr);
                if (!ReferenceEquals(spannedColumn, columnExpr))
                {
                    // If so, then update the dictionary of column index to span information
                    if (null == spannedColumns)
                    {
                        spannedColumns = new Dictionary <int, DbExpression>();
                    }

                    spannedColumns[idx] = spannedColumn;
                }
                else
                {
                    // Otherwise, update the dictionary of column index to unmodified expression
                    if (null == unmodifiedColumns)
                    {
                        unmodifiedColumns = new Dictionary <int, DbExpression>();
                    }

                    unmodifiedColumns[idx] = columnExpr;
                }
            }

            // A new expression need only be built if at least one column was spanned
            if (null == spannedColumns)
            {
                // No columns were spanned, indicate that the original expression should remain.
                return(expression);
            }
            else
            {
                // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns.
                var columnArguments = new List <DbExpression>(rowType.Properties.Count);
                var properties      = new List <EdmProperty>(rowType.Properties.Count);
                for (var idx = 0; idx < rowType.Properties.Count; idx++)
                {
                    var          columnProp = rowType.Properties[idx];
                    DbExpression columnDef  = null;
                    if (!spannedColumns.TryGetValue(idx, out columnDef))
                    {
                        columnDef = unmodifiedColumns[idx];
                    }
                    columnArguments.Add(columnDef);
                    properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType));
                }

                // Copy over any eLinq initializer metadata (if present, or null if not).
                // Note that this initializer metadata does not strictly match the new row type
                // that includes spanned columns, but will be correct once the object materializer
                // has interpreted the query results to produce the correct value for each colum.
                var          rewrittenRow          = new RowType(properties, rowType.InitializerMetadata);
                var          rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow);
                DbExpression rewritten             = rewrittenRowTypeUsage.New(columnArguments);

                // SQLBUDT #554182: If we insert a new projection we should make sure to
                // not interfere with the nullability of the input.
                // In particular, if the input row is null and we construct a new row as a projection over its columns
                // we would get a row consisting of nulls, instead of a null row.
                // Thus, given an input X, we rewritte it as:  if (X is null) then NULL else rewritten.
                if (newRow == null)
                {
                    DbExpression condition      = expression.IsNull();
                    DbExpression nullExpression = rewrittenRowTypeUsage.Null();
                    rewritten = DbExpressionBuilder.Case(
                        new List <DbExpression>(new[] { condition }),
                        new List <DbExpression>(new[] { nullExpression }),
                        rewritten);
                }

                // Add an entry to the spanned row type => original row type map for the new row type.
                AddSpannedRowType(rewrittenRow, expression.ResultType);

                if (lambdaExpression != null &&
                    newRow != null)
                {
                    rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments);
                }

                return(rewritten);
            }
        }
Example #19
0
        private DbExpression GenerateStructuralTypeResultMappingView(DbExpression storeFunctionInvoke, IList <EdmSchemaError> errors, out DiscriminatorMap discriminatorMap)
        {
            Debug.Assert(m_structuralTypeMappings != null && m_structuralTypeMappings.Count > 0, "m_structuralTypeMappings != null && m_structuralTypeMappings.Count > 0");

            discriminatorMap = null;

            // Process explicit structural type mappings. The mapping is based on the direct call of the store function
            // wrapped into a projection constructing the mapped structural types.

            DbExpression queryExpression = storeFunctionInvoke;

            if (m_structuralTypeMappings.Count == 1)
            {
                var mapping = m_structuralTypeMappings[0];

                var type             = mapping.Item1;
                var conditions       = mapping.Item2;
                var propertyMappings = mapping.Item3;

                if (conditions.Count > 0)
                {
                    queryExpression = queryExpression.Where((row) => GenerateStructuralTypeConditionsPredicate(conditions, row));
                }

                var binding = queryExpression.BindAs("row");
                var entityTypeMappingView = GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable, errors);
                if (entityTypeMappingView == null)
                {
                    return(null);
                }

                queryExpression = binding.Project(entityTypeMappingView);
            }
            else
            {
                var binding = queryExpression.BindAs("row");

                // Make sure type projection is performed over a closed set where each row is guaranteed to produce a known type.
                // To do this, filter the store function output using the type conditions.
                Debug.Assert(m_structuralTypeMappings.All(m => m.Item2.Count > 0), "In multi-type mapping each type must have conditions.");
                List <DbExpression> structuralTypePredicates = m_structuralTypeMappings.Select(m => GenerateStructuralTypeConditionsPredicate(m.Item2, binding.Variable)).ToList();
                queryExpression = binding.Filter(Helpers.BuildBalancedTreeInPlace(
                                                     structuralTypePredicates.ToArray(), // clone, otherwise BuildBalancedTreeInPlace will change it
                                                     (prev, next) => prev.Or(next)));
                binding = queryExpression.BindAs("row");

                List <DbExpression> structuralTypeMappingViews = new List <DbExpression>(m_structuralTypeMappings.Count);
                foreach (var mapping in m_structuralTypeMappings)
                {
                    var type             = mapping.Item1;
                    var propertyMappings = mapping.Item3;

                    var structuralTypeMappingView = GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable, errors);
                    if (structuralTypeMappingView == null)
                    {
                        continue;
                    }
                    else
                    {
                        structuralTypeMappingViews.Add(structuralTypeMappingView);
                    }
                }
                Debug.Assert(structuralTypeMappingViews.Count == structuralTypePredicates.Count, "structuralTypeMappingViews.Count == structuralTypePredicates.Count");
                if (structuralTypeMappingViews.Count != m_structuralTypeMappings.Count)
                {
                    Debug.Assert(errors.Count > 0, "errors.Count > 0");
                    return(null);
                }

                // Because we are projecting over the closed set, we can convert the last WHEN THEN into ELSE.
                DbExpression typeConstructors = DbExpressionBuilder.Case(
                    structuralTypePredicates.Take(m_structuralTypeMappings.Count - 1),
                    structuralTypeMappingViews.Take(m_structuralTypeMappings.Count - 1),
                    structuralTypeMappingViews[m_structuralTypeMappings.Count - 1]);

                queryExpression = binding.Project(typeConstructors);

                if (DiscriminatorMap.TryCreateDiscriminatorMap(this.FunctionImport.EntitySet, queryExpression, out discriminatorMap))
                {
                    Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created");
                }
            }

            return(queryExpression);
        }
Example #20
0
        private DbExpression RewriteCollection(DbExpression expression)
        {
            var target = expression;

            // If the collection expression is a project expression, get a strongly typed reference to it for later use.
            DbProjectExpression project = null;

            if (DbExpressionKind.Project
                == expression.ExpressionKind)
            {
                project = (DbProjectExpression)expression;
                target  = project.Input.Expression;
            }

            // If Relationship span is enabled and the source of this collection is (directly or indirectly)
            // a RelationshipNavigation operation, it may be possible to optimize the relationship span rewrite
            // for the Entities produced by the navigation.
            NavigationInfo navInfo = null;

            if (RelationshipSpan)
            {
                // Attempt to find a RelationshipNavigationExpression in the collection-defining expression
                target = RelationshipNavigationVisitor.FindNavigationExpression(target, _aliasGenerator, out navInfo);
            }

            // If a relationship navigation expression defines this collection, make the Ref that is the navigation source
            // and the source association end available for possible use when the projection over the collection is rewritten.
            if (navInfo != null)
            {
                EnterNavigationCollection(navInfo);
            }
            else
            {
                // Otherwise, add a null navigation info instance to the stack to indicate that relationship navigation
                // cannot be optimized for the entities produced by this collection expression (if it is a collection of entities).
                EnterCollection();
            }

            // If the expression is already a DbProjectExpression then simply visit the projection,
            // instead of introducing another projection over the existing one.
            var result = expression;

            if (project != null)
            {
                var newProjection = Rewrite(project.Projection);
                if (!ReferenceEquals(project.Projection, newProjection))
                {
                    result = target.BindAs(project.Input.VariableName).Project(newProjection);
                }
            }
            else
            {
                // This is not a recognized special case, so simply add the span projection over the original
                // collection-producing expression, if it is required.
                var          collectionBinding = target.BindAs(_aliasGenerator.Next());
                DbExpression projection        = collectionBinding.Variable;

                var spannedProjection = Rewrite(projection);

                if (!ReferenceEquals(projection, spannedProjection))
                {
                    result = collectionBinding.Project(spannedProjection);
                }
            }

            // Remove any navigation information from scope, if it was added
            ExitCollection();

            // If a navigation expression defines this collection and its navigation information was used to
            // short-circuit relationship span rewrites, then enclose the entire rewritten expression in a
            // Lambda binding that brings the source Ref of the navigation operation into scope. This ref is
            // refered to by VariableReferenceExpressions in the original navigation expression as well as any
            // short-circuited relationship span columns in the rewritten expression.
            if (navInfo != null &&
                navInfo.InUse)
            {
                // Create a Lambda function that binds the original navigation source expression under the variable name
                // used in the navigation expression and the relationship span columns, and which has its Lambda body
                // defined by the rewritten collection expression.
                var formals = new List <DbVariableReferenceExpression>(1);
                formals.Add(navInfo.SourceVariable);

                var args = new List <DbExpression>(1);
                args.Add(navInfo.Source);

                result = DbExpressionBuilder.Lambda(result, formals).Invoke(args);
            }

            // Return the (possibly rewritten) collection expression.
            return(result);
        }
Example #21
0
        /// <summary>
        /// Visit a Member Expression.  Creates a mapping of the MemberExpression to a DbPropertyExpression
        /// which is a reference to the table/column name that matches the MemberExpression.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMember(MemberExpression node)
        {
#if (DEBUG_VISITS)
            System.Diagnostics.Debug.Print("VisitMember: {0}, expression.NodeType={1}, Member={2}", node, node.Expression.NodeType, node.Member);
#endif

            var expression = base.VisitMember(node) as MemberExpression;

            if ((expression.Expression.NodeType == ExpressionType.Parameter) && (expression.Expression.Type.IsClass || expression.Expression.Type.IsInterface))
            {
                //  expression is a reference to a class/interface property.  Need to map it to a sql parameter or look up
                //  the existing parameter.
                //  The class/interface is defined by expression.Expression while the property is in expression.Member.
                string propertyName;
                if (IsNullableType(expression.Member.ReflectedType))
                {
                    var subExpression = expression.Expression as MemberExpression;
                    propertyName = subExpression.Member.Name;
                }
                else
                {
                    propertyName = expression.Member.Name;
                }

                //  TODO: To support different class/interfaces, can we figure out the correct binding from what's in expression.Expression?
                var edmType = _Binding.VariableType.EdmType as EntityType;

                DbPropertyExpression propertyExpression;
                if (!_Properties.TryGetValue(propertyName, out propertyExpression))
                {
                    //  Not created yet

                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    EdmMember edmProp;
                    if (_DataSpace == DataSpace.CSpace)
                    {
                        edmProp = edmType.Members.FirstOrDefault(m => m.Name == propertyName);
                    }
                    else
                    {
                        edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(propertyName))).FirstOrDefault();
                    }

                    if (edmProp == null)
                    {
                        //  If using SSpace: Accessing properties outside the main entity is not supported and will cause this exception.
                        //  If using CSpace: Navigation properties are handled (and will be found above)
                        throw new ApplicationException(string.Format("Property {0} not found in Entity Type {1}", propertyName, expression.Expression.Type.Name));
                    }

                    //  If edmProp is a navigation property (only available when using CSpace), EF will automatically add the join to it when it sees we are referencing this property.
                    propertyExpression = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(_Binding.VariableType, _Binding.VariableName), edmProp.Name);
                    _Properties.Add(propertyName, propertyExpression);

#if (DEBUG_VISITS)
                    System.Diagnostics.Debug.Print("Created new property expression for {0}", propertyName);
#endif
                }

                //  Nothing else to do here
                MapExpressionToDbExpression(expression, propertyExpression);
                return(expression);
            }

            //  We are accessing a member property such that expression.Expression is the object and expression.Member is the property.
            //  And the property is one that requires special handling.  Regular class properties are all handled up above.
            var objectExpression = GetDbExpressionForExpression(expression.Expression);

            DbExpression dbExpression;
            var          isNullableType = IsNullableType(expression.Expression.Type);
            int?         dummy;
            if (isNullableType && (expression.Member.Name == nameof(dummy.HasValue)))
            {
                //  Map HasValue to !IsNull
                dbExpression = DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(objectExpression));
            }
            else if (isNullableType && (expression.Member.Name == nameof(dummy.Value)))
            {
                //  This is a nullable Value accessor so just map to the object itself and it will be mapped for us
                dbExpression = objectExpression;
            }
            else
            {
                if (_DataSpace == DataSpace.CSpace)
                {
                    //  When using CSpace, we can map a property to the class member and EF will figure out the relationship for us.
                    dbExpression = DbExpressionBuilder.Property(objectExpression, expression.Member.Name);
                }
                else
                {
                    //  When using SSpace, we cannot access class members
                    throw new ApplicationException(string.Format("Unhandled property accessor in expression: {0}", expression));
                }
            }

            MapExpressionToDbExpression(expression, dbExpression);
            return(expression);
        }
        protected virtual IEnumerable <MigrationStatement> Generate(HistoryOperation operation)
        {
            foreach (var commandTree in operation.CommandTrees)
            {
                List <DbParameter> _;

                switch (commandTree.CommandTreeKind)
                {
                case DbCommandTreeKind.Insert:
                    const int MigrationIdColumn = 0;
                    const int ContextKeyColumn  = 1;
                    const int ModelColumn       = 2;
                    const int VersionColumn     = 3;
                    const int MaxChunkLength    = 32000;

                    var dbInsert  = (DbInsertCommandTree)commandTree;
                    var modelData = ((dbInsert.SetClauses[ModelColumn] as DbSetClause).Value as DbConstantExpression).Value as byte[];

                    // If model length is less than max value, stick to original version
                    if (modelData.Length < MaxChunkLength)
                    {
                        using (var writer = SqlWriter())
                        {
                            writer.Write(DmlSqlGenerator.GenerateInsertSql(dbInsert, out _, generateParameters: false));
                            yield return(Statement(writer));
                        }
                    }
                    else
                    {
                        // If it's bigger - we split it into chunks, as big as possible
                        var dataChunks = modelData.Split(MaxChunkLength);

                        // We can't change CommandTree, but we can create new one, only difference being data length
                        using (var writer = SqlWriter())
                        {
                            var setClauses = new ReadOnlyCollection <DbModificationClause>(
                                new List <DbModificationClause>
                            {
                                dbInsert.SetClauses[MigrationIdColumn],
                                dbInsert.SetClauses[ContextKeyColumn],
                                DbExpressionBuilder.SetClause(
                                    ((DbSetClause)dbInsert.SetClauses[ModelColumn]).Property,
                                    dataChunks.ElementAt(0).ToArray()
                                    ),
                                dbInsert.SetClauses[VersionColumn],
                            });


                            var newCommandTree = new DbInsertCommandTree(dbInsert.MetadataWorkspace, commandTree.DataSpace, dbInsert.Target, setClauses, dbInsert.Returning);

                            writer.Write(DmlSqlGenerator.GenerateInsertSql(newCommandTree, out _, generateParameters: false));
                            yield return(Statement(writer));
                        }

                        // Now we have first Insert, let's update it with chunks of remaing data
                        foreach (var dataChunk in dataChunks.Skip(1))
                        {
                            using (var writer = SqlWriter())
                            {
                                var modelProperty = (dbInsert.SetClauses[ModelColumn] as DbSetClause).Property as DbPropertyExpression;

                                var modificationClauses = new List <DbModificationClause>
                                {
                                    // Updating existing chunk of data with subsequent part
                                    DbExpressionBuilder.SetClause(
                                        modelProperty,
                                        // TODO: Better solution required
                                        // Best if we could use DbExpression.Concat, but it returns DbFunctionExpression, which is not supported
                                        // Here we'll get SET Model = 'data', which we can update as text later
                                        dataChunk.ToArray()
                                        )
                                }.AsReadOnly();

                                var updateCommandTree = new DbUpdateCommandTree(dbInsert.MetadataWorkspace,
                                                                                dbInsert.DataSpace,
                                                                                dbInsert.Target,
                                                                                // Predicate is MigrationId value
                                                                                DbExpressionBuilder.Equal(
                                                                                    ((DbSetClause)dbInsert.SetClauses[MigrationIdColumn]).Property,
                                                                                    ((DbSetClause)dbInsert.SetClauses[MigrationIdColumn]).Value),
                                                                                modificationClauses,
                                                                                dbInsert.Returning);

                                writer.Write(DmlSqlGenerator.GenerateUpdateSql(updateCommandTree, out _, generateParameters: false));

                                // Since we couldn't concat before, replacing query as string
                                // Replacing SET Model = 'data'
                                //		with SET Model = Model || 'data'
                                // Model being first is important, since these are parts of single value
                                var statement    = writer.ToString();
                                var newStatement = statement.Replace($"SET \"{modelProperty.Property.Name}\" = ", $"SET \"{modelProperty.Property.Name}\" = \"{modelProperty.Property.Name}\" || ");

                                yield return(Statement(newStatement));
                            }
                        }
                    }
                    break;

                case DbCommandTreeKind.Delete:
                    using (var writer = SqlWriter())
                    {
                        writer.Write(DmlSqlGenerator.GenerateDeleteSql((DbDeleteCommandTree)commandTree, out _, generateParameters: false));
                        yield return(Statement(writer));
                    }
                    break;
                }
            }
        }
Example #23
0
        private Expression MapStartsWithExpression(MethodCallExpression node)
        {
            var expression = base.VisitMethodCall(node) as MethodCallExpression;

            if ((expression.Arguments == null) || (expression.Arguments.Count != 1))
            {
                throw new ApplicationException("Did not find exactly 1 Argument to StartsWith 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 StartsWith cannot be null");
                }

                dbExpression = DbExpressionBuilder.Like(srcExpression, DbExpressionBuilder.Constant(constantExpression.Value.ToString() + "%"));
            }
            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.Like(srcExpression, argExpression.Concat(DbExpressionBuilder.Constant("%")));
            }

            MapExpressionToDbExpression(expression, dbExpression);
            return(expression);
        }
Example #24
0
        protected virtual DbCommand CreateCommand(Dictionary <int, object> identifierValues)
        {
            DbModificationCommandTree modificationCommandTree = this._modificationCommandTree;

            if (this._inputIdentifiers != null)
            {
                Dictionary <DbSetClause, DbSetClause> clauseMappings = new Dictionary <DbSetClause, DbSetClause>();
                for (int index = 0; index < this._inputIdentifiers.Count; ++index)
                {
                    KeyValuePair <int, DbSetClause> inputIdentifier = this._inputIdentifiers[index];
                    object obj;
                    if (identifierValues.TryGetValue(inputIdentifier.Key, out obj))
                    {
                        DbSetClause dbSetClause = new DbSetClause(inputIdentifier.Value.Property, (DbExpression)DbExpressionBuilder.Constant(obj));
                        clauseMappings[inputIdentifier.Value] = dbSetClause;
                        this._inputIdentifiers[index]         = new KeyValuePair <int, DbSetClause>(inputIdentifier.Key, dbSetClause);
                    }
                }
                modificationCommandTree = DynamicUpdateCommand.RebuildCommandTree(modificationCommandTree, clauseMappings);
            }
            return(this.Translator.CreateCommand(modificationCommandTree));
        }
Example #25
0
        protected override Expression VisitBinary(BinaryExpression node)
        {
#if (DEBUG_VISITS)
            System.Diagnostics.Debug.Print("VisitBinary: {0}", node);
#endif

            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 = DbExpressionBuilder.Equal(leftExpression, rightExpression);
                    }
                    break;

                case ExpressionType.NotEqual:
                    dbExpression = DbExpressionBuilder.NotEqual(leftExpression, rightExpression);
                    break;

                case ExpressionType.GreaterThan:
                    dbExpression = DbExpressionBuilder.GreaterThan(leftExpression, rightExpression);
                    break;

                case ExpressionType.GreaterThanOrEqual:
                    dbExpression = DbExpressionBuilder.GreaterThanOrEqual(leftExpression, rightExpression);
                    break;

                case ExpressionType.LessThan:
                    dbExpression = DbExpressionBuilder.LessThan(leftExpression, rightExpression);
                    break;

                case ExpressionType.LessThanOrEqual:
                    dbExpression = DbExpressionBuilder.LessThanOrEqual(leftExpression, rightExpression);
                    break;

                case ExpressionType.AndAlso:
                    dbExpression = DbExpressionBuilder.And(leftExpression, rightExpression);
                    break;

                case ExpressionType.OrElse:
                    dbExpression = DbExpressionBuilder.Or(leftExpression, rightExpression);
                    break;

                case ExpressionType.And:
                    dbExpression = EdmFunctions.BitwiseAnd(leftExpression, rightExpression);
                    break;

                case ExpressionType.Or:
                    dbExpression = EdmFunctions.BitwiseOr(leftExpression, rightExpression);
                    break;

                case ExpressionType.ExclusiveOr:
                    dbExpression = EdmFunctions.BitwiseXor(leftExpression, rightExpression);
                    break;

                case ExpressionType.Coalesce:
                    //  EF does not expose the "coalesce" function.  So best we can do is a case statement.  Issue #77.
                    var whenExpressions = new List <DbExpression>()
                    {
                        DbExpressionBuilder.IsNull(leftExpression)
                    };
                    var thenExpressions = new List <DbExpression>()
                    {
                        rightExpression
                    };
                    dbExpression = DbExpressionBuilder.Case(whenExpressions, thenExpressions, leftExpression);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unhandled NodeType of {0} in LambdaToDbExpressionVisitor.VisitBinary", expression.NodeType));
                }
            }

            MapExpressionToDbExpression(expression, dbExpression);

            return(expression);
        }
Example #26
0
        // <summary>
        // Gets DB command definition encapsulating store logic for this command.
        // </summary>
        protected virtual DbCommand CreateCommand(Dictionary <int, object> identifierValues)
        {
            var commandTree = _modificationCommandTree;

            // check if any server gen identifiers need to be set
            if (null != _inputIdentifiers)
            {
                var modifiedClauses = new Dictionary <DbSetClause, DbSetClause>();
                for (var idx = 0; idx < _inputIdentifiers.Count; idx++)
                {
                    var inputIdentifier = _inputIdentifiers[idx];

                    object value;
                    if (identifierValues.TryGetValue(inputIdentifier.Key, out value))
                    {
                        // reset the value of the identifier
                        var newClause = new DbSetClause(inputIdentifier.Value.Property, DbExpressionBuilder.Constant(value));
                        modifiedClauses[inputIdentifier.Value] = newClause;
                        _inputIdentifiers[idx] = new KeyValuePair <int, DbSetClause>(inputIdentifier.Key, newClause);
                    }
                }
                commandTree = RebuildCommandTree(commandTree, modifiedClauses);
            }

            return(Translator.CreateCommand(commandTree));
        }
Example #27
0
        public void CreateDbCommandDefinition_converts_legacy_ProviderIncompatibleException_to_non_legacy_ProviderIncompatibleException()
        {
            var expectedException = new InvalidOperationException("Test");

            try
            {
                var mockProviderServices = new Mock <SystemDataCommon.DbProviderServices>();
                mockProviderServices
                .Protected()
                .Setup("CreateDbCommandDefinition", ItExpr.IsAny <SystemDataCommon.DbProviderManifest>(), ItExpr.IsAny <DbCommandTree>())
                .Throws(expectedException);

                new LegacyDbProviderServicesWrapper(mockProviderServices.Object)
                .CreateCommandDefinition(
                    new LegacyDbProviderManifestWrapper(LegacyProviderManifest),
                    new DbQueryCommandTree(CreateMetadataWorkspace(), DataSpace.SSpace, DbExpressionBuilder.Constant(42), false));

                throw new InvalidOperationException("Expected exception but none thrown.");
            }
            catch (ProviderIncompatibleException exception)
            {
                Assert.Same(expectedException, exception.InnerException);
            }
        }
        //  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, false);

                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.
                            var currentBaseType = baseResult.ResultType.EdmType.BaseType;
                            while (entitySet == null && currentBaseType != null)
                            {
                                entitySet = containers.EntitySets.FirstOrDefault(e => e.ElementType.Name == currentBaseType.Name);

                                if (entitySet == null)
                                {
                                    currentBaseType = currentBaseType.BaseType;
                                }
                            }

                            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);
        }
Example #29
0
        // <summary>
        // Determines column/value used to set values for a row.
        // </summary>
        // <remarks>
        // The following columns are not included in the result:
        // <list>
        //     <item>Keys in non-insert operations (keys are only set for inserts).</item>
        //     <item>Values flagged 'preserve' (these are values the propagator claims are untouched).</item>
        //     <item>Server generated values.</item>
        // </list>
        // </remarks>
        // <param name="target"> Expression binding representing the table. </param>
        // <param name="row"> Row containing values to set. </param>
        // <param name="processor"> Context for table. </param>
        // <param name="insertMode"> Determines whether key columns and 'preserve' columns are omitted from the list. </param>
        // <param name="outputIdentifiers"> Dictionary listing server generated identifiers. </param>
        // <param name="returning"> DbExpression describing result projection for server generated values. </param>
        // <param name="rowMustBeTouched"> Indicates whether the row must be touched because it produces a value (e.g. computed) </param>
        // <returns> Column value pairs. </returns>
        private IEnumerable <DbModificationClause> BuildSetClauses(
            DbExpressionBinding target, PropagatorResult row,
            PropagatorResult originalRow, TableChangeProcessor processor, bool insertMode, out Dictionary <int, string> outputIdentifiers,
            out DbExpression returning,
            ref bool rowMustBeTouched)
        {
            var setClauses         = new Dictionary <EdmProperty, PropagatorResult>();
            var returningArguments = new List <KeyValuePair <string, DbExpression> >();

            outputIdentifiers = new Dictionary <int, string>();

            // Determine which flags indicate a property should be omitted from the set list.
            var omitMask = insertMode
                               ? PropagatorFlags.NoFlags
                               : PropagatorFlags.Preserve | PropagatorFlags.Unknown;

            for (var propertyOrdinal = 0; propertyOrdinal < processor.Table.ElementType.Properties.Count; propertyOrdinal++)
            {
                var property = processor.Table.ElementType.Properties[propertyOrdinal];

                // Type members and result values are ordinally aligned
                var propertyResult = row.GetMemberValue(propertyOrdinal);

                if (PropagatorResult.NullIdentifier
                    != propertyResult.Identifier)
                {
                    // retrieve principal value
                    propertyResult = propertyResult.ReplicateResultWithNewValue(
                        m_translator.KeyManager.GetPrincipalValue(propertyResult));
                }

                var omitFromSetList = false;

                Debug.Assert(propertyResult.IsSimple);

                // Determine if this is a key value
                var isKey = false;
                for (var i = 0; i < processor.KeyOrdinals.Length; i++)
                {
                    if (processor.KeyOrdinals[i] == propertyOrdinal)
                    {
                        isKey = true;
                        break;
                    }
                }

                // check if this value should be omitted
                var flags = PropagatorFlags.NoFlags;
                if (!insertMode && isKey)
                {
                    // Keys are only set for inserts
                    omitFromSetList = true;
                }
                else
                {
                    // See if this value has been marked up with some context. If so, add the flag information
                    // from the markup. Markup includes information about whether the property is a concurrency value,
                    // whether it is known (it may be a property that is preserved across an update for instance)
                    flags |= propertyResult.PropagatorFlags;
                }

                // Determine if this value is server-generated
                var genPattern  = MetadataHelper.GetStoreGeneratedPattern(property);
                var isServerGen = genPattern == StoreGeneratedPattern.Computed ||
                                  (insertMode && genPattern == StoreGeneratedPattern.Identity);
                if (isServerGen)
                {
                    var propertyExpression = target.Variable.Property(property);
                    returningArguments.Add(new KeyValuePair <string, DbExpression>(property.Name, propertyExpression));

                    // check if this is a server generated identifier
                    var identifier = propertyResult.Identifier;
                    if (PropagatorResult.NullIdentifier != identifier)
                    {
                        if (m_translator.KeyManager.HasPrincipals(identifier))
                        {
                            throw new InvalidOperationException(Strings.Update_GeneratedDependent(property.Name));
                        }
                        outputIdentifiers.Add(identifier, property.Name);

                        // If this property maps an identifier (in the update pipeline) it may
                        // also be a store key. If so, the pattern had better be "Identity"
                        // since otherwise we're dealing with a mutable key.
                        if (genPattern != StoreGeneratedPattern.Identity
                            &&
                            processor.IsKeyProperty(propertyOrdinal))
                        {
                            throw new NotSupportedException(
                                      Strings.Update_NotSupportedComputedKeyColumn(
                                          EdmProviderManifest.StoreGeneratedPatternFacetName,
                                          XmlConstants.Computed,
                                          XmlConstants.Identity,
                                          property.Name,
                                          property.DeclaringType.FullName));
                        }
                    }
                }

                if (PropagatorFlags.NoFlags
                    != (flags & (omitMask)))
                {
                    // column value matches "omit" pattern, therefore should not be set
                    omitFromSetList = true;
                }
                else if (isServerGen)
                {
                    // column value does not match "omit" pattern, but it is server generated
                    // so it cannot be set
                    omitFromSetList = true;

                    // if the row has a modified value overridden by server gen,
                    // it must still be touched in order to retrieve the value
                    rowMustBeTouched = true;
                }

                // make the user is not updating an identity value
                if (!omitFromSetList &&
                    !insertMode &&
                    genPattern == StoreGeneratedPattern.Identity)
                {
                    //throw the error only if the value actually changed
                    Debug.Assert(originalRow != null, "Updated records should have a original row");
                    var originalPropertyResult = originalRow.GetMemberValue(propertyOrdinal);
                    Debug.Assert(originalPropertyResult.IsSimple, "Server Gen property that is not primitive?");
                    Debug.Assert(propertyResult.IsSimple, "Server Gen property that is not primitive?");

                    if (!ByValueEqualityComparer.Default.Equals(originalPropertyResult.GetSimpleValue(), propertyResult.GetSimpleValue()))
                    {
                        throw new InvalidOperationException(
                                  Strings.Update_ModifyingIdentityColumn(
                                      XmlConstants.Identity,
                                      property.Name,
                                      property.DeclaringType.FullName));
                    }
                    else
                    {
                        omitFromSetList = true;
                    }
                }

                if (!omitFromSetList)
                {
                    setClauses.Add(property, propertyResult);
                }
            }

            // Construct returning projection
            if (0 < returningArguments.Count)
            {
                returning = DbExpressionBuilder.NewRow(returningArguments);
            }
            else
            {
                returning = null;
            }

            // Construct clauses corresponding to the set clauses
            var result = new List <DbModificationClause>(setClauses.Count);

            foreach (var setClause in setClauses)
            {
                result.Add(
                    new DbSetClause(
                        GeneratePropertyExpression(target, setClause.Key),
                        GenerateValueExpression(setClause.Key, setClause.Value)));
            }

            return(result);
        }
Example #30
0
 public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
 {
     if (interceptionContext.Result.DataSpace == DataSpace.SSpace &&
         interceptionContext.DbContexts.All(con => con.GetType().GetCustomAttribute <TrackDisabledAttribute>() == null))
     {
         #region Query
         var queryCommand = interceptionContext.Result as DbQueryCommandTree;
         if (queryCommand != null)
         {
             var newQuery = queryCommand.Query.Accept(new TrackingQueryVisitor());
             interceptionContext.Result = new DbQueryCommandTree(
                 queryCommand.MetadataWorkspace,
                 queryCommand.DataSpace,
                 newQuery);
         }
         #endregion
         #region Delete
         var deleteCommand = interceptionContext.Result as DbDeleteCommandTree;
         if (deleteCommand != null)
         {
             var bitColumn      = ColumnAnnotationAttribute.GetColumnName <TrackDeletedBitAttribute>(deleteCommand.Target.VariableType.EdmType);
             var dateColumn     = ColumnAnnotationAttribute.GetColumnName <TrackDeletedDateAttribute>(deleteCommand.Target.VariableType.EdmType);
             var identityColumn = ColumnAnnotationAttribute.GetColumnName <TrackDeletedIdentityAttribute>(deleteCommand.Target.VariableType.EdmType);
             var clauses        = new List <DbModificationClause>();
             if (bitColumn != null)
             {
                 clauses.Add(DbExpressionBuilder.SetClause(deleteCommand.Target.Variable.Property(bitColumn), DbExpression.FromBoolean(true)));
                 if (dateColumn != null)
                 {
                     clauses.Add(DbExpressionBuilder.SetClause(deleteCommand.Target.Variable.Property(dateColumn), DbExpression.FromDateTimeOffset(TimeZoneInfo.ConvertTime(timeProvider.NowOffsetted().Add(_dateTimeAdjustment), getCurrentTimeZoneFunction()))));
                 }
                 if (identityColumn != null)
                 {
                     clauses.Add(DbExpressionBuilder.SetClause(deleteCommand.Target.Variable.Property(identityColumn), DbExpression.FromString(getCurrentIdentityFunction())));
                 }
             }
             if (clauses.Count > 0)
             {
                 //Add this constant clause to trace deletions on update command
                 clauses.Add(DbExpressionBuilder.SetClause(DbExpressionBuilder.Constant(137), DbExpressionBuilder.Constant(137)));
                 interceptionContext.Result = new DbUpdateCommandTree(
                     deleteCommand.MetadataWorkspace,
                     deleteCommand.DataSpace,
                     deleteCommand.Target,
                     deleteCommand.Predicate,
                     clauses.AsReadOnly(),
                     null);
             }
         }
         #endregion
         #region Insert
         var insertCommand = interceptionContext.Result as DbInsertCommandTree;
         if (insertCommand != null)
         {
             var dateColumn     = ColumnAnnotationAttribute.GetColumnName <TrackCreatedDateAttribute>(insertCommand.Target.VariableType.EdmType);
             var identityColumn = ColumnAnnotationAttribute.GetColumnName <TrackCreatedIdentityAttribute>(insertCommand.Target.VariableType.EdmType);
             var clauses        = insertCommand.SetClauses.ToList();
             RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedBitAttribute>(insertCommand.Target.VariableType.EdmType));
             RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedDateAttribute>(insertCommand.Target.VariableType.EdmType));
             RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedIdentityAttribute>(insertCommand.Target.VariableType.EdmType));
             RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackModifiedDateAttribute>(insertCommand.Target.VariableType.EdmType));
             RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackModifiedIdentityAttribute>(insertCommand.Target.VariableType.EdmType));
             if (dateColumn != null)
             {
                 AddOrReplaceClause(clauses, DbExpressionBuilder.SetClause(insertCommand.Target.Variable.Property(dateColumn), DbExpression.FromDateTimeOffset(TimeZoneInfo.ConvertTime(timeProvider.NowOffsetted().Add(_dateTimeAdjustment), getCurrentTimeZoneFunction()))));
             }
             if (identityColumn != null)
             {
                 AddOrReplaceClause(clauses, DbExpressionBuilder.SetClause(insertCommand.Target.Variable.Property(identityColumn), DbExpression.FromString(getCurrentIdentityFunction())));
             }
             if (dateColumn != null || (identityColumn != null))
             {
                 interceptionContext.Result = new DbInsertCommandTree(
                     insertCommand.MetadataWorkspace,
                     insertCommand.DataSpace,
                     insertCommand.Target,
                     clauses.AsReadOnly(),
                     null);
             }
         }
         #endregion
         #region Update
         var updateCommand = interceptionContext.Result as DbUpdateCommandTree;
         if (updateCommand != null)
         {
             var dateColumn            = ColumnAnnotationAttribute.GetColumnName <TrackModifiedDateAttribute>(updateCommand.Target.VariableType.EdmType);
             var identityColumn        = ColumnAnnotationAttribute.GetColumnName <TrackModifiedIdentityAttribute>(updateCommand.Target.VariableType.EdmType);
             var clauses               = updateCommand.SetClauses.ToList();
             var traceDeleteionsClause = clauses.FirstOrDefault(c =>
                                                                ((DbSetClause)c).Property is DbConstantExpression && ((DbConstantExpression)((DbSetClause)c).Property).Value is int && ((int)((DbConstantExpression)((DbSetClause)c).Property).Value) == 137 &&
                                                                ((DbSetClause)c).Value is DbConstantExpression && ((DbConstantExpression)((DbSetClause)c).Value).Value is int && ((int)((DbConstantExpression)((DbSetClause)c).Value).Value) == 137
                                                                );
             if (traceDeleteionsClause != null)
             {
                 //This command is derived from a deletion operation
                 clauses.Remove(traceDeleteionsClause);
             }
             else
             {
                 RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedBitAttribute>(updateCommand.Target.VariableType.EdmType));
                 RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedDateAttribute>(updateCommand.Target.VariableType.EdmType));
                 RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackDeletedIdentityAttribute>(updateCommand.Target.VariableType.EdmType));
                 RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackCreatedDateAttribute>(updateCommand.Target.VariableType.EdmType));
                 RemoveClause(clauses, ColumnAnnotationAttribute.GetColumnName <TrackCreatedIdentityAttribute>(updateCommand.Target.VariableType.EdmType));
                 if (dateColumn != null)
                 {
                     AddOrReplaceClause(clauses, DbExpressionBuilder.SetClause(updateCommand.Target.Variable.Property(dateColumn), DbExpression.FromDateTimeOffset(TimeZoneInfo.ConvertTime(timeProvider.NowOffsetted().Add(_dateTimeAdjustment), getCurrentTimeZoneFunction()))));
                 }
                 if (identityColumn != null)
                 {
                     AddOrReplaceClause(clauses, DbExpressionBuilder.SetClause(updateCommand.Target.Variable.Property(identityColumn), DbExpression.FromString(getCurrentIdentityFunction())));
                 }
             }
             if (dateColumn != null || (identityColumn != null))
             {
                 interceptionContext.Result = new DbUpdateCommandTree(
                     updateCommand.MetadataWorkspace,
                     updateCommand.DataSpace,
                     updateCommand.Target,
                     updateCommand.Predicate,
                     clauses.AsReadOnly(),
                     null);
             }
         }
         #endregion
     }
 }