// <summary> // Generates CQT for the current <see cref="CaseStatement" />. // </summary> internal DbExpression AsCqt(DbExpression row, IEnumerable <WithRelationship> withRelationships) { // Generate the Case WHEN .. THEN ..., WHEN ... THEN ..., END var conditions = new List <DbExpression>(); var values = new List <DbExpression>(); foreach (var clause in Clauses) { conditions.Add(clause.Condition.AsCqt(row)); values.Add(CaseSlotValueAsCqt(row, clause.Value, MemberPath, withRelationships)); } // Generate ELSE var elseValue = ElseValue != null ? CaseSlotValueAsCqt(row, ElseValue, MemberPath, withRelationships) : Constant.Null.AsCqt(row, MemberPath); if (Clauses.Count > 0) { return(DbExpressionBuilder.Case(conditions, values, elseValue)); } else { Debug.Assert(elseValue != null, "CASE statement with no WHEN/THENs must have ELSE."); return(elseValue); } }
internal static CqtExpression StripNull(LinqExpression sourceExpression, DbExpression inputExpression, DbExpression outputExpression, bool useDatabaseNullSemantics) { if (sourceExpression.IsNullConstant()) { return(DbExpressionBuilder.Constant(string.Empty)); } if (sourceExpression.NodeType == ExpressionType.Constant) { return(outputExpression); } if (useDatabaseNullSemantics) { return(outputExpression); } // converts evaluated null values to empty string, nullable primitive properties etc. var castNullToEmptyString = DbExpressionBuilder.Case( new[] { inputExpression.IsNull() }, new[] { DbExpressionBuilder.Constant(string.Empty) }, outputExpression); return(castNullToEmptyString); }
private static DbExpression SimplifyCaseStatement(DbExpression expression) { var caseExpression = (DbCaseExpression)expression; // try simplifying predicates var predicateSimplified = false; var rewrittenPredicates = new List <DbExpression>(caseExpression.When.Count); foreach (var when in caseExpression.When) { DbExpression simplifiedPredicate; if (TrySimplifyPredicate(when, out simplifiedPredicate)) { rewrittenPredicates.Add(simplifiedPredicate); predicateSimplified = true; } else { rewrittenPredicates.Add(when); } } if (!predicateSimplified) { return(null); } caseExpression = DbExpressionBuilder.Case(rewrittenPredicates, caseExpression.Then, caseExpression.Else); return(caseExpression); }
private static DbExpression SimplifyCaseStatement(DbExpression expression) { DbCaseExpression dbCaseExpression = (DbCaseExpression)expression; bool flag = false; List <DbExpression> dbExpressionList = new List <DbExpression>(dbCaseExpression.When.Count); foreach (DbExpression predicate in (IEnumerable <DbExpression>)dbCaseExpression.When) { DbExpression simplified; if (ViewSimplifier.TrySimplifyPredicate(predicate, out simplified)) { dbExpressionList.Add(simplified); flag = true; } else { dbExpressionList.Add(predicate); } } if (!flag) { return((DbExpression)null); } return((DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>)dbExpressionList, (IEnumerable <DbExpression>)dbCaseExpression.Then, dbCaseExpression.Else)); }
internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember) { if (m_expr.IsTrue || m_expr.IsFalse) { return(m_expr.AsCqt(row)); } else { // Produce "CASE WHEN boolExpr THEN True ELSE False END" in order to enforce the two-state boolean logic: // if boolExpr returns the boolean Unknown, it gets converted to boolean False. return(DbExpressionBuilder.Case(new DbExpression[] { m_expr.AsCqt(row) }, new DbExpression[] { DbExpressionBuilder.True }, DbExpressionBuilder.False)); } }
internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember) { if (this.m_expr.IsTrue || this.m_expr.IsFalse) { return(this.m_expr.AsCqt(row)); } return((DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>) new DbExpression[1] { this.m_expr.AsCqt(row) }, (IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)DbExpressionBuilder.True }, (DbExpression)DbExpressionBuilder.False)); }
internal DbExpression AsCqt( DbExpression row, IEnumerable <WithRelationship> withRelationships) { List <DbExpression> dbExpressionList1 = new List <DbExpression>(); List <DbExpression> dbExpressionList2 = new List <DbExpression>(); foreach (CaseStatement.WhenThen clause in this.Clauses) { dbExpressionList1.Add(clause.Condition.AsCqt(row)); dbExpressionList2.Add(CaseStatement.CaseSlotValueAsCqt(row, clause.Value, this.MemberPath, withRelationships)); } DbExpression elseExpression = this.ElseValue != null?CaseStatement.CaseSlotValueAsCqt(row, this.ElseValue, this.MemberPath, withRelationships) : Constant.Null.AsCqt(row, this.MemberPath); if (this.Clauses.Count > 0) { return((DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>)dbExpressionList1, (IEnumerable <DbExpression>)dbExpressionList2, elseExpression)); } return(elseExpression); }
private DbExpression GenerateStructuralTypeResultMappingView( DbExpression storeFunctionInvoke, out DiscriminatorMap discriminatorMap) { discriminatorMap = (DiscriminatorMap)null; DbExpression dbExpression = storeFunctionInvoke; DbExpression queryView; if (this.m_structuralTypeMappings.Count == 1) { Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > structuralTypeMapping = this.m_structuralTypeMappings[0]; StructuralType structuralType = structuralTypeMapping.Item1; List <ConditionPropertyMapping> conditions = structuralTypeMapping.Item2; List <PropertyMapping> propertyMappings = structuralTypeMapping.Item3; if (conditions.Count > 0) { dbExpression = (DbExpression)dbExpression.Where((Func <DbExpression, DbExpression>)(row => FunctionImportMappingComposable.GenerateStructuralTypeConditionsPredicate(conditions, row))); } DbExpressionBinding input = dbExpression.BindAs("row"); DbExpression structuralTypeMappingView = FunctionImportMappingComposable.GenerateStructuralTypeMappingView(structuralType, propertyMappings, (DbExpression)input.Variable); queryView = (DbExpression)input.Project(structuralTypeMappingView); } else { DbExpressionBinding binding = dbExpression.BindAs("row"); List <DbExpression> list = this.m_structuralTypeMappings.Select <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >, DbExpression>((Func <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >, DbExpression>)(m => FunctionImportMappingComposable.GenerateStructuralTypeConditionsPredicate(m.Item2, (DbExpression)binding.Variable))).ToList <DbExpression>(); binding = binding.Filter(Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>)list.ToArray(), (Func <DbExpression, DbExpression, DbExpression>)((prev, next) => (DbExpression)prev.Or(next)))).BindAs("row"); List <DbExpression> source = new List <DbExpression>(this.m_structuralTypeMappings.Count); foreach (Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > structuralTypeMapping in this.m_structuralTypeMappings) { StructuralType structuralType = structuralTypeMapping.Item1; List <PropertyMapping> propertyMappings = structuralTypeMapping.Item3; source.Add(FunctionImportMappingComposable.GenerateStructuralTypeMappingView(structuralType, propertyMappings, (DbExpression)binding.Variable)); } DbExpression projection = (DbExpression)DbExpressionBuilder.Case(list.Take <DbExpression>(this.m_structuralTypeMappings.Count - 1), source.Take <DbExpression>(this.m_structuralTypeMappings.Count - 1), source[this.m_structuralTypeMappings.Count - 1]); queryView = (DbExpression)binding.Project(projection); DiscriminatorMap.TryCreateDiscriminatorMap(this.FunctionImport.EntitySet, queryView, out discriminatorMap); } return(queryView); }
public void Visit_DbCaseExpression_creates_equivalent_legacy_DbCaseExpression() { var whens = new[] { DbExpressionBuilder.Constant(42).NotEqual(DbExpressionBuilder.Constant(42)), DbExpressionBuilder.Constant(911).Equal(DbExpressionBuilder.Constant(911)), }; var thens = new[] { DbExpressionBuilder.False, DbExpressionBuilder.True }; var caseExpression = DbExpressionBuilder.Case(whens, thens, DbExpressionBuilder.False); var legacyCaseExpression = _legacyDbExpressionConverter.Visit(caseExpression) as LegacyCommandTrees.DbCaseExpression; Assert.NotNull(legacyCaseExpression); Assert.Equal(LegacyCommandTrees.DbExpressionKind.Case, legacyCaseExpression.ExpressionKind); Assert.Equal(2, legacyCaseExpression.When.Count); Assert.Equal(LegacyCommandTrees.DbExpressionKind.NotEquals, legacyCaseExpression.When[0].ExpressionKind); Assert.Equal(LegacyCommandTrees.DbExpressionKind.Equals, legacyCaseExpression.When[1].ExpressionKind); Assert.Equal(2, legacyCaseExpression.Then.Count); Assert.False((bool)((LegacyCommandTrees.DbConstantExpression)legacyCaseExpression.Then[0]).Value); Assert.True((bool)((LegacyCommandTrees.DbConstantExpression)legacyCaseExpression.Then[1]).Value); Assert.False((bool)((LegacyCommandTrees.DbConstantExpression)legacyCaseExpression.Else).Value); TypeUsageVerificationHelper .VerifyTypeUsagesEquivalent(legacyCaseExpression.ResultType, caseExpression.ResultType); }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression 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 (int idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column EdmProperty 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); } DbExpression spannedColumn = this.Rewrite(columnExpr); if (!object.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. List <DbExpression> columnArguments = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> properties = new List <EdmProperty>(rowType.Properties.Count); for (int idx = 0; idx < rowType.Properties.Count; idx++) { EdmProperty 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. RowType rewrittenRow = new RowType(properties, rowType.InitializerMetadata); TypeUsage rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow); DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments); // SQLBUDT #554182: If we insert a new projection we should 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 = DbExpressionBuilder.CreateIsNullExpressionAllowingRowTypeArgument(expression); DbExpression nullExpression = DbExpressionBuilder.Null(rewrittenRowTypeUsage); rewritten = DbExpressionBuilder.Case( new List <DbExpression>(new DbExpression[] { condition }), new List <DbExpression>(new DbExpression[] { 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); } }
private DbExpression GenerateStructuralTypeResultMappingView( DbExpression storeFunctionInvoke, 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. var 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); 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."); var 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"); var structuralTypeMappingViews = new List <DbExpression>(m_structuralTypeMappings.Count); foreach (var mapping in m_structuralTypeMappings) { var type = mapping.Item1; var propertyMappings = mapping.Item3; structuralTypeMappingViews.Add(GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable)); } Debug.Assert( structuralTypeMappingViews.Count == structuralTypePredicates.Count, "structuralTypeMappingViews.Count == structuralTypePredicates.Count"); // 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(FunctionImport.EntitySet, queryExpression, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } return(queryExpression); }
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); }
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); }
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); }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression instanceExpression = lambdaExpression == null ? expression as DbNewInstanceExpression : lambdaExpression.Lambda.Body as DbNewInstanceExpression; Dictionary <int, DbExpression> dictionary1 = (Dictionary <int, DbExpression>)null; Dictionary <int, DbExpression> dictionary2 = (Dictionary <int, DbExpression>)null; for (int index = 0; index < rowType.Properties.Count; ++index) { EdmProperty property = rowType.Properties[index]; DbExpression expression1 = instanceExpression == null ? (DbExpression)expression.Property(property.Name) : instanceExpression.Arguments[index]; DbExpression dbExpression = this.Rewrite(expression1); if (!object.ReferenceEquals((object)dbExpression, (object)expression1)) { if (dictionary2 == null) { dictionary2 = new Dictionary <int, DbExpression>(); } dictionary2[index] = dbExpression; } else { if (dictionary1 == null) { dictionary1 = new Dictionary <int, DbExpression>(); } dictionary1[index] = expression1; } } if (dictionary2 == null) { return(expression); } List <DbExpression> dbExpressionList = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> edmPropertyList = new List <EdmProperty>(rowType.Properties.Count); for (int key = 0; key < rowType.Properties.Count; ++key) { EdmProperty property = rowType.Properties[key]; DbExpression dbExpression = (DbExpression)null; if (!dictionary2.TryGetValue(key, out dbExpression)) { dbExpression = dictionary1[key]; } dbExpressionList.Add(dbExpression); edmPropertyList.Add(new EdmProperty(property.Name, dbExpression.ResultType)); } RowType spannedType = new RowType((IEnumerable <EdmProperty>)edmPropertyList, rowType.InitializerMetadata); TypeUsage typeUsage = TypeUsage.Create((EdmType)spannedType); DbExpression dbExpression1 = (DbExpression)typeUsage.New((IEnumerable <DbExpression>)dbExpressionList); if (instanceExpression == null) { dbExpression1 = (DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)expression.IsNull() }), (IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)typeUsage.Null() }), dbExpression1); } this.AddSpannedRowType(spannedType, expression.ResultType); if (lambdaExpression != null && instanceExpression != null) { dbExpression1 = (DbExpression)DbLambda.Create(dbExpression1, (IEnumerable <DbVariableReferenceExpression>)lambdaExpression.Lambda.Variables).Invoke((IEnumerable <DbExpression>)lambdaExpression.Arguments); } return(dbExpression1); }
private DbExpression AddFkRelatedEntityRefs(DbExpression viewConstructor) { if (this.doNotProcess) { return((DbExpression)null); } if (this.extent.BuiltInTypeKind != BuiltInTypeKind.EntitySet || this.extent.EntityContainer.DataSpace != DataSpace.CSpace) { this.doNotProcess = true; return((DbExpression)null); } EntitySet targetSet = (EntitySet)this.extent; List <AssociationSet> list1 = targetSet.EntityContainer.BaseEntitySets.Where <EntitySetBase>((Func <EntitySetBase, bool>)(es => es.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)).Cast <AssociationSet>().Where <AssociationSet>((Func <AssociationSet, bool>)(assocSet => { if (assocSet.ElementType.IsForeignKey) { return(assocSet.AssociationSetEnds.Any <AssociationSetEnd>((Func <AssociationSetEnd, bool>)(se => se.EntitySet == targetSet))); } return(false); })).ToList <AssociationSet>(); if (list1.Count == 0) { this.doNotProcess = true; return((DbExpression)null); } HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> > source = new HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >(); foreach (AssociationSet associationSet in list1) { ReferentialConstraint referentialConstraint = associationSet.ElementType.ReferentialConstraints[0]; AssociationSetEnd associationSetEnd1 = associationSet.AssociationSetEnds[referentialConstraint.ToRole.Name]; if (associationSetEnd1.EntitySet == targetSet) { EntityType elementType = (EntityType)TypeHelpers.GetEdmType <RefType>(associationSetEnd1.CorrespondingAssociationEndMember.TypeUsage).ElementType; AssociationSetEnd associationSetEnd2 = associationSet.AssociationSetEnds[referentialConstraint.FromRole.Name]; source.Add(Tuple.Create <EntityType, AssociationSetEnd, ReferentialConstraint>(elementType, associationSetEnd2, referentialConstraint)); } } if (source.Count == 0) { this.doNotProcess = true; return((DbExpression)null); } DbProjectExpression projectExpression = (DbProjectExpression)viewConstructor; List <DbNewInstanceExpression> instanceExpressionList = new List <DbNewInstanceExpression>(); List <DbExpression> dbExpressionList1 = (List <DbExpression>)null; if (projectExpression.Projection.ExpressionKind == DbExpressionKind.Case) { DbCaseExpression projection = (DbCaseExpression)projectExpression.Projection; dbExpressionList1 = new List <DbExpression>(projection.When.Count); for (int index = 0; index < projection.When.Count; ++index) { dbExpressionList1.Add(projection.When[index]); instanceExpressionList.Add((DbNewInstanceExpression)projection.Then[index]); } instanceExpressionList.Add((DbNewInstanceExpression)projection.Else); } else { instanceExpressionList.Add((DbNewInstanceExpression)projectExpression.Projection); } bool flag = false; for (int index = 0; index < instanceExpressionList.Count; ++index) { DbNewInstanceExpression entityConstructor = instanceExpressionList[index]; EntityType constructedEntityType = TypeHelpers.GetEdmType <EntityType>(entityConstructor.ResultType); List <DbRelatedEntityRef> list2 = source.Where <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >((Func <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, bool>)(psdt => { if (constructedEntityType != psdt.Item1) { return(constructedEntityType.IsSubtypeOf((EdmType)psdt.Item1)); } return(true); })).Select <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, DbRelatedEntityRef>((Func <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, DbRelatedEntityRef>)(psdt => ViewSimplifier.RelatedEntityRefFromAssociationSetEnd(constructedEntityType, entityConstructor, psdt.Item2, psdt.Item3))).ToList <DbRelatedEntityRef>(); if (list2.Count > 0) { if (entityConstructor.HasRelatedEntityReferences) { list2 = entityConstructor.RelatedEntityReferences.Concat <DbRelatedEntityRef>((IEnumerable <DbRelatedEntityRef>)list2).ToList <DbRelatedEntityRef>(); } entityConstructor = DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(constructedEntityType, entityConstructor.Arguments, (IList <DbRelatedEntityRef>)list2); instanceExpressionList[index] = entityConstructor; flag = true; } } DbExpression dbExpression = (DbExpression)null; if (flag) { if (dbExpressionList1 != null) { List <DbExpression> dbExpressionList2 = new List <DbExpression>(dbExpressionList1.Count); List <DbExpression> dbExpressionList3 = new List <DbExpression>(dbExpressionList1.Count); for (int index = 0; index < dbExpressionList1.Count; ++index) { dbExpressionList2.Add(dbExpressionList1[index]); dbExpressionList3.Add((DbExpression)instanceExpressionList[index]); } dbExpression = (DbExpression)projectExpression.Input.Project((DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>)dbExpressionList2, (IEnumerable <DbExpression>)dbExpressionList3, (DbExpression)instanceExpressionList[dbExpressionList1.Count])); } else { dbExpression = (DbExpression)projectExpression.Input.Project((DbExpression)instanceExpressionList[0]); } } this.doNotProcess = true; return(dbExpression); }
private static DbExpression SimplifyNestedTphDiscriminator(DbExpression expression) { DbProjectExpression projectExpression = (DbProjectExpression)expression; DbFilterExpression booleanColumnFilter = (DbFilterExpression)projectExpression.Input.Expression; DbProjectExpression expression1 = (DbProjectExpression)booleanColumnFilter.Input.Expression; DbFilterExpression expression2 = (DbFilterExpression)expression1.Input.Expression; List <DbExpression> list1 = ViewSimplifier.FlattenOr(booleanColumnFilter.Predicate).ToList <DbExpression>(); List <DbPropertyExpression> list2 = list1.OfType <DbPropertyExpression>().Where <DbPropertyExpression>((Func <DbPropertyExpression, bool>)(px => { if (px.Instance.ExpressionKind == DbExpressionKind.VariableReference) { return(((DbVariableReferenceExpression)px.Instance).VariableName == booleanColumnFilter.Input.VariableName); } return(false); })).ToList <DbPropertyExpression>(); if (list1.Count != list2.Count) { return((DbExpression)null); } List <string> list3 = list2.Select <DbPropertyExpression, string>((Func <DbPropertyExpression, string>)(px => px.Property.Name)).ToList <string>(); Dictionary <object, DbComparisonExpression> discriminatorPredicates = new Dictionary <object, DbComparisonExpression>(); if (!TypeSemantics.IsEntityType(expression2.Input.VariableType) || !ViewSimplifier.TryMatchDiscriminatorPredicate(expression2, (Action <DbComparisonExpression, object>)((compEx, discValue) => discriminatorPredicates.Add(discValue, compEx)))) { return((DbExpression)null); } EdmProperty property1 = (EdmProperty)((DbPropertyExpression)discriminatorPredicates.First <KeyValuePair <object, DbComparisonExpression> >().Value.Left).Property; DbNewInstanceExpression projection1 = (DbNewInstanceExpression)expression1.Projection; RowType edmType = TypeHelpers.GetEdmType <RowType>(projection1.ResultType); Dictionary <string, DbComparisonExpression> dictionary1 = new Dictionary <string, DbComparisonExpression>(); Dictionary <string, DbComparisonExpression> dictionary2 = new Dictionary <string, DbComparisonExpression>(); Dictionary <string, DbExpression> propertyValues = new Dictionary <string, DbExpression>(projection1.Arguments.Count); for (int index = 0; index < projection1.Arguments.Count; ++index) { string name = edmType.Properties[index].Name; DbExpression dbExpression = projection1.Arguments[index]; if (list3.Contains(name)) { if (dbExpression.ExpressionKind != DbExpressionKind.Case) { return((DbExpression)null); } DbCaseExpression dbCaseExpression = (DbCaseExpression)dbExpression; if (dbCaseExpression.When.Count != 1 || !TypeSemantics.IsBooleanType(dbCaseExpression.Then[0].ResultType) || (!TypeSemantics.IsBooleanType(dbCaseExpression.Else.ResultType) || dbCaseExpression.Then[0].ExpressionKind != DbExpressionKind.Constant) || (dbCaseExpression.Else.ExpressionKind != DbExpressionKind.Constant || !(bool)((DbConstantExpression)dbCaseExpression.Then[0]).Value || (bool)((DbConstantExpression)dbCaseExpression.Else).Value)) { return((DbExpression)null); } DbPropertyExpression property2; object key; if (!ViewSimplifier.TryMatchPropertyEqualsValue(dbCaseExpression.When[0], expression1.Input.VariableName, out property2, out key) || property2.Property != property1 || !discriminatorPredicates.ContainsKey(key)) { return((DbExpression)null); } dictionary1.Add(name, discriminatorPredicates[key]); dictionary2.Add(name, (DbComparisonExpression)dbCaseExpression.When[0]); } else { propertyValues.Add(name, dbExpression); } } DbExpression predicate = Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>)dictionary1.Values), (Func <DbExpression, DbExpression, DbExpression>)((left, right) => (DbExpression)left.Or(right))); DbFilterExpression input = expression2.Input.Filter(predicate); DbCaseExpression projection2 = (DbCaseExpression)projectExpression.Projection; List <DbExpression> dbExpressionList1 = new List <DbExpression>(projection2.When.Count); List <DbExpression> dbExpressionList2 = new List <DbExpression>(projection2.Then.Count); for (int index = 0; index < projection2.When.Count; ++index) { DbPropertyExpression propertyExpression = (DbPropertyExpression)projection2.When[index]; DbNewInstanceExpression instanceExpression = (DbNewInstanceExpression)projection2.Then[index]; DbComparisonExpression comparisonExpression; if (!dictionary2.TryGetValue(propertyExpression.Property.Name, out comparisonExpression)) { return((DbExpression)null); } dbExpressionList1.Add((DbExpression)comparisonExpression); DbExpression dbExpression = ViewSimplifier.ValueSubstituter.Substitute((DbExpression)instanceExpression, projectExpression.Input.VariableName, propertyValues); dbExpressionList2.Add(dbExpression); } DbExpression elseExpression = ViewSimplifier.ValueSubstituter.Substitute(projection2.Else, projectExpression.Input.VariableName, propertyValues); DbCaseExpression dbCaseExpression1 = DbExpressionBuilder.Case((IEnumerable <DbExpression>)dbExpressionList1, (IEnumerable <DbExpression>)dbExpressionList2, elseExpression); return((DbExpression)input.BindAs(expression1.Input.VariableName).Project((DbExpression)dbCaseExpression1)); }
internal static DbExpression ConvertToString(ExpressionConverter parent, LinqExpression linqExpression) { if (linqExpression.Type == typeof(object)) { var constantExpression = linqExpression as ConstantExpression; linqExpression = constantExpression != null? Expression.Constant(constantExpression.Value) : linqExpression.RemoveConvert(); } var expression = parent.TranslateExpression(linqExpression); var clrType = TypeSystem.GetNonNullableType(linqExpression.Type); if (clrType.IsEnum) { //Flag enums are not supported. if (Attribute.IsDefined(clrType, typeof(FlagsAttribute))) { throw new NotSupportedException(Strings.Elinq_ToStringNotSupportedForEnumsWithFlags); } if (linqExpression.IsNullConstant()) { return(DbExpressionBuilder.Constant(string.Empty)); } //Constant expression, optimize to constant name if (linqExpression.NodeType == ExpressionType.Constant) { var value = ((ConstantExpression)linqExpression).Value; var name = Enum.GetName(clrType, value) ?? value.ToString(); return(DbExpressionBuilder.Constant(name)); } var integralType = clrType.GetEnumUnderlyingType(); var type = parent.GetValueLayerType(integralType); var values = clrType.GetEnumValues() .Cast <object>() .Select(v => System.Convert.ChangeType(v, integralType, CultureInfo.InvariantCulture)) //cast to integral type so that unmapped enum types works too .Select(v => DbExpressionBuilder.Constant(v)) .Select(c => (DbExpression)expression.CastTo(type).Equal(c)) //cast expression to integral type before comparing to constant .Concat(new[] { expression.CastTo(type).IsNull() }); // default case var names = clrType.GetEnumNames() .Select(s => DbExpressionBuilder.Constant(s)) .Concat(new[] { DbExpressionBuilder.Constant(string.Empty) }); // default case //translate unnamed enum values for the else clause, raw linq -> as integral value -> translate to cqt -> to string //e.g. ((DayOfWeek)99) -> "99" var asIntegralLinq = LinqExpression.Convert(linqExpression, integralType); var asStringCqt = parent .TranslateExpression(asIntegralLinq) .CastTo(parent.GetValueLayerType(typeof(string))); return(DbExpressionBuilder.Case(values, names, asStringCqt)); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.String)) { return(StripNull(linqExpression, expression, expression)); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.Guid)) { return(StripNull(linqExpression, expression, expression.CastTo(parent.GetValueLayerType(typeof(string))).ToLower())); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.Boolean)) { if (linqExpression.IsNullConstant()) { return(DbExpressionBuilder.Constant(string.Empty)); } if (linqExpression.NodeType == ExpressionType.Constant) { var name = ((ConstantExpression)linqExpression).Value.ToString(); return(DbExpressionBuilder.Constant(name)); } var whenTrue = expression.Equal(DbExpressionBuilder.True); var whenFalse = expression.Equal(DbExpressionBuilder.False); var thenTrue = DbExpressionBuilder.Constant(true.ToString()); var thenFalse = DbExpressionBuilder.Constant(false.ToString()); return(DbExpressionBuilder.Case( new[] { whenTrue, whenFalse }, new[] { thenTrue, thenFalse }, DbExpressionBuilder.Constant(string.Empty))); } else { if (!SupportsCastToString(expression.ResultType)) { throw new NotSupportedException( Strings.Elinq_ToStringNotSupportedForType(expression.ResultType.EdmType.Name)); } //treat all other types as a simple cast return(StripNull(linqExpression, expression, expression.CastTo(parent.GetValueLayerType(typeof(string))))); } }