// <summary> // Creates generated view object for the combination of the <paramref name="extent" /> and the <paramref name="type" />. // This constructor is used for regular cell-based view generation. // </summary> internal static GeneratedView CreateGeneratedView( EntitySetBase extent, EdmType type, DbQueryCommandTree commandTree, string eSQL, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config) { // If config.GenerateEsql is specified, eSQL must be non-null. // If config.GenerateEsql is false, commandTree is non-null except the case when loading pre-compiled eSQL views. Debug.Assert(!config.GenerateEsql || !String.IsNullOrEmpty(eSQL), "eSQL must be specified"); DiscriminatorMap discriminatorMap = null; if (commandTree != null) { commandTree = ViewSimplifier.SimplifyView(extent, commandTree); // See if the view matches the "discriminated" pattern (allows simplification of generated store commands) if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } } return(new GeneratedView(extent, type, commandTree, eSQL, discriminatorMap, mappingItemCollection, config)); }
internal ExplicitDiscriminatorMap(DiscriminatorMap template) { m_typeMap = template.TypeMap; m_discriminatorProperty = template.Discriminator.Property; m_properties = new ReadOnlyCollection<EdmProperty>(template.PropertyMap.Select(propertyValuePair => propertyValuePair.Key) .ToList()); }
private GeneratedView( EntitySetBase extent, EdmType type, DbQueryCommandTree commandTree, string eSQL, DiscriminatorMap discriminatorMap, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config) { this.m_extent = extent; this.m_type = type; this.m_commandTree = commandTree; this.m_eSQL = eSQL; this.m_discriminatorMap = discriminatorMap; this.m_mappingItemCollection = mappingItemCollection; this.m_config = config; if (!this.m_config.IsViewTracing) { return; } StringBuilder builder = new StringBuilder(1024); this.ToCompactString(builder); Helpers.FormatTraceLine("CQL view for {0}", (object)builder.ToString()); }
private GeneratedView( EntitySetBase extent, EdmType type, DbQueryCommandTree commandTree, string eSQL, DiscriminatorMap discriminatorMap, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config) { // At least one of the commandTree or eSQL must be specified. // Both are specified in the case of user-defined views. Debug.Assert(commandTree != null || !String.IsNullOrEmpty(eSQL), "commandTree or eSQL must be specified"); m_extent = extent; m_type = type; m_commandTree = commandTree; m_eSQL = eSQL; m_discriminatorMap = discriminatorMap; m_mappingItemCollection = mappingItemCollection; m_config = config; if (m_config.IsViewTracing) { var trace = new StringBuilder(1024); ToCompactString(trace); Helpers.FormatTraceLine("CQL view for {0}", trace.ToString()); } }
internal ExplicitDiscriminatorMap(DiscriminatorMap template) { m_typeMap = template.TypeMap; m_discriminatorProperty = template.Discriminator.Property; m_properties = template.PropertyMap.Select(propertyValuePair => propertyValuePair.Key) .ToList().AsReadOnly(); }
private static bool ExpressionsCompatible(DbExpression x, DbExpression y) { if (x.ExpressionKind != y.ExpressionKind) { return(false); } switch (x.ExpressionKind) { case DbExpressionKind.NewInstance: DbNewInstanceExpression instanceExpression1 = (DbNewInstanceExpression)x; DbNewInstanceExpression instanceExpression2 = (DbNewInstanceExpression)y; if (!instanceExpression1.ResultType.EdmType.EdmEquals((MetadataItem)instanceExpression2.ResultType.EdmType)) { return(false); } for (int index = 0; index < instanceExpression1.Arguments.Count; ++index) { if (!DiscriminatorMap.ExpressionsCompatible(instanceExpression1.Arguments[index], instanceExpression2.Arguments[index])) { return(false); } } return(true); case DbExpressionKind.Property: DbPropertyExpression propertyExpression1 = (DbPropertyExpression)x; DbPropertyExpression propertyExpression2 = (DbPropertyExpression)y; if (propertyExpression1.Property == propertyExpression2.Property) { return(DiscriminatorMap.ExpressionsCompatible(propertyExpression1.Instance, propertyExpression2.Instance)); } return(false); case DbExpressionKind.Ref: DbRefExpression dbRefExpression1 = (DbRefExpression)x; DbRefExpression dbRefExpression2 = (DbRefExpression)y; if (dbRefExpression1.EntitySet.EdmEquals((MetadataItem)dbRefExpression2.EntitySet)) { return(DiscriminatorMap.ExpressionsCompatible(dbRefExpression1.Argument, dbRefExpression2.Argument)); } return(false); case DbExpressionKind.VariableReference: return(((DbVariableReferenceExpression)x).VariableName == ((DbVariableReferenceExpression)y).VariableName); default: return(false); } }
private static bool TryParseView( string eSQL, bool isUserSpecified, EntitySetBase extent, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config, out DbQueryCommandTree commandTree, out DiscriminatorMap discriminatorMap, out Exception parserException) { commandTree = (DbQueryCommandTree)null; discriminatorMap = (DiscriminatorMap)null; parserException = (Exception)null; config.StartSingleWatch(PerfType.ViewParsing); try { ParserOptions.CompilationMode compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (isUserSpecified) { compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode; } commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode); commandTree = ViewSimplifier.SimplifyView(extent, commandTree); if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap); } } catch (Exception ex) { if (ex.IsCatchableExceptionType()) { parserException = ex; } else { throw; } } finally { config.StopSingleWatch(PerfType.ViewParsing); } return(parserException == null); }
internal static GeneratedView CreateGeneratedView( EntitySetBase extent, EdmType type, DbQueryCommandTree commandTree, string eSQL, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config) { DiscriminatorMap discriminatorMap = (DiscriminatorMap)null; if (commandTree != null) { commandTree = ViewSimplifier.SimplifyView(extent, commandTree); if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap); } } return(new GeneratedView(extent, type, commandTree, eSQL, discriminatorMap, mappingItemCollection, config)); }
/// <summary> /// Determines whether the given query view matches the discriminator map pattern. /// </summary> internal static bool TryCreateDiscriminatorMap(EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap) { discriminatorMap = null; if (queryView.ExpressionKind != DbExpressionKind.Project) { return false; } var project = (DbProjectExpression)queryView; if (project.Projection.ExpressionKind != DbExpressionKind.Case) { return false; } var caseExpression = (DbCaseExpression)project.Projection; if (project.Projection.ResultType.EdmType.BuiltInTypeKind != BuiltInTypeKind.EntityType) { return false; } // determine value domain by walking filter if (project.Input.Expression.ExpressionKind != DbExpressionKind.Filter) { return false; } var filterExpression = (DbFilterExpression)project.Input.Expression; var discriminatorDomain = new HashSet<object>(); if ( !ViewSimplifier.TryMatchDiscriminatorPredicate( filterExpression, (equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue))) { return false; } var typeMap = new List<KeyValuePair<object, EntityType>>(); var propertyMap = new Dictionary<EdmProperty, DbExpression>(); var relPropertyMap = new Dictionary<RelProperty, DbExpression>(); var typeToRelPropertyMap = new Dictionary<EntityType, List<RelProperty>>(); DbPropertyExpression discriminator = null; EdmProperty discriminatorProperty = null; for (var i = 0; i < caseExpression.When.Count; i++) { var when = caseExpression.When[i]; var then = caseExpression.Then[i]; var projectionVariableName = project.Input.VariableName; DbPropertyExpression currentDiscriminator; object discriminatorValue; if ( !ViewSimplifier.TryMatchPropertyEqualsValue( when, projectionVariableName, out currentDiscriminator, out discriminatorValue)) { return false; } // must be the same discriminator in every case if (null == discriminatorProperty) { discriminatorProperty = (EdmProperty)currentDiscriminator.Property; } else if (discriminatorProperty != currentDiscriminator.Property) { return false; } discriminator = currentDiscriminator; // right hand side must be entity type constructor EntityType currentType; if (!TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out currentType)) { return false; } // remember type + discriminator value typeMap.Add(new KeyValuePair<object, EntityType>(discriminatorValue, currentType)); // remove discriminator value from domain discriminatorDomain.Remove(discriminatorValue); } // make sure only one member of discriminator domain remains... if (1 != discriminatorDomain.Count) { return false; } // check default case EntityType elseType; if (null == caseExpression.Else || !TryMatchEntityTypeConstructor(caseExpression.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out elseType)) { return false; } typeMap.Add(new KeyValuePair<object, EntityType>(discriminatorDomain.Single(), elseType)); // Account for cases where some type in the hierarchy specifies a rel-property, but another // type in the hierarchy does not if (!CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap)) { return false; } // since the store may right-pad strings, ensure discriminator values are unique in their trimmed // form var discriminatorValues = typeMap.Select(map => map.Key); var uniqueValueCount = discriminatorValues.Distinct(TrailingSpaceComparer.Instance).Count(); var valueCount = typeMap.Count; if (uniqueValueCount != valueCount) { return false; } discriminatorMap = new DiscriminatorMap(discriminator, typeMap, propertyMap, relPropertyMap, entitySet); return true; }
// <summary> // Given an extent and its corresponding view, invokes the parser to check if the view definition is syntactically correct. // Iff parsing succeeds: <paramref name="commandTree" /> and <paramref name="discriminatorMap" /> are set to the parse result and method returns true, // otherwise if parser has thrown a catchable exception, it is returned via <paramref name="parserException" /> parameter, // otherwise exception is re-thrown. // </summary> private static bool TryParseView( string eSQL, bool isUserSpecified, EntitySetBase extent, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config, out DbQueryCommandTree commandTree, out DiscriminatorMap discriminatorMap, out Exception parserException) { commandTree = null; discriminatorMap = null; parserException = null; // We do not catch any internal exceptions any more config.StartSingleWatch(PerfType.ViewParsing); try { // If it is a user specified view, allow all queries. Otherwise parse the view in the restricted mode. var compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (isUserSpecified) { compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode; } Debug.Assert(!String.IsNullOrEmpty(eSQL), "eSQL query is not specified"); commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode); commandTree = ViewSimplifier.SimplifyView(extent, commandTree); // See if the view matches the "discriminated" pattern (allows simplification of generated store commands) if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } } catch (Exception e) { // Catching all the exception types since Query parser seems to be throwing a variety of // exceptions - EntityException, ArgumentException, ArgumentNullException etc. if (e.IsCatchableExceptionType()) { parserException = e; } else { throw; } } finally { config.StopSingleWatch(PerfType.ViewParsing); } Debug.Assert(commandTree != null || parserException != null, "Either commandTree or parserException is expected."); // Note: m_commandTree might have been initialized by a previous call to this method, so in consequent calls it might occur that // both m_commandTree and parserException are not null - this would mean that the last parse attempt failed, but m_commandTree value is // preserved from the previous call. return(parserException == null); }
// <summary> // Determines whether the given query view matches the discriminator map pattern. // </summary> internal static bool TryCreateDiscriminatorMap(EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap) { discriminatorMap = null; if (queryView.ExpressionKind != DbExpressionKind.Project) { return(false); } var project = (DbProjectExpression)queryView; if (project.Projection.ExpressionKind != DbExpressionKind.Case) { return(false); } var caseExpression = (DbCaseExpression)project.Projection; if (project.Projection.ResultType.EdmType.BuiltInTypeKind != BuiltInTypeKind.EntityType) { return(false); } // determine value domain by walking filter if (project.Input.Expression.ExpressionKind != DbExpressionKind.Filter) { return(false); } var filterExpression = (DbFilterExpression)project.Input.Expression; var discriminatorDomain = new HashSet <object>(); if ( !ViewSimplifier.TryMatchDiscriminatorPredicate( filterExpression, (equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue))) { return(false); } var typeMap = new List <KeyValuePair <object, EntityType> >(); var propertyMap = new Dictionary <EdmProperty, DbExpression>(); var relPropertyMap = new Dictionary <RelProperty, DbExpression>(); var typeToRelPropertyMap = new Dictionary <EntityType, List <RelProperty> >(); DbPropertyExpression discriminator = null; EdmProperty discriminatorProperty = null; for (var i = 0; i < caseExpression.When.Count; i++) { var when = caseExpression.When[i]; var then = caseExpression.Then[i]; var projectionVariableName = project.Input.VariableName; DbPropertyExpression currentDiscriminator; object discriminatorValue; if ( !ViewSimplifier.TryMatchPropertyEqualsValue( when, projectionVariableName, out currentDiscriminator, out discriminatorValue)) { return(false); } // must be the same discriminator in every case if (null == discriminatorProperty) { discriminatorProperty = (EdmProperty)currentDiscriminator.Property; } else if (discriminatorProperty != currentDiscriminator.Property) { return(false); } discriminator = currentDiscriminator; // right hand side must be entity type constructor EntityType currentType; if (!TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out currentType)) { return(false); } // remember type + discriminator value typeMap.Add(new KeyValuePair <object, EntityType>(discriminatorValue, currentType)); // remove discriminator value from domain discriminatorDomain.Remove(discriminatorValue); } // make sure only one member of discriminator domain remains... if (1 != discriminatorDomain.Count) { return(false); } // check default case EntityType elseType; if (null == caseExpression.Else || !TryMatchEntityTypeConstructor(caseExpression.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out elseType)) { return(false); } typeMap.Add(new KeyValuePair <object, EntityType>(discriminatorDomain.Single(), elseType)); // Account for cases where some type in the hierarchy specifies a rel-property, but another // type in the hierarchy does not if (!CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap)) { return(false); } // since the store may right-pad strings, ensure discriminator values are unique in their trimmed // form var discriminatorValues = typeMap.Select(map => map.Key); var uniqueValueCount = discriminatorValues.Distinct(TrailingSpaceComparer.Instance).Count(); var valueCount = typeMap.Count; if (uniqueValueCount != valueCount) { return(false); } discriminatorMap = new DiscriminatorMap(discriminator, typeMap, propertyMap, relPropertyMap, entitySet); return(true); }
private static bool TryMatchEntityTypeConstructor( DbExpression then, Dictionary <EdmProperty, DbExpression> propertyMap, Dictionary <RelProperty, DbExpression> relPropertyMap, Dictionary <EntityType, List <RelProperty> > typeToRelPropertyMap, out EntityType entityType) { if (then.ExpressionKind != DbExpressionKind.NewInstance) { entityType = (EntityType)null; return(false); } DbNewInstanceExpression instanceExpression = (DbNewInstanceExpression)then; entityType = (EntityType)instanceExpression.ResultType.EdmType; for (int index = 0; index < entityType.Properties.Count; ++index) { EdmProperty property = entityType.Properties[index]; DbExpression x = instanceExpression.Arguments[index]; DbExpression y; if (propertyMap.TryGetValue(property, out y)) { if (!DiscriminatorMap.ExpressionsCompatible(x, y)) { return(false); } } else { propertyMap.Add(property, x); } } if (instanceExpression.HasRelatedEntityReferences) { List <RelProperty> relPropertyList; if (!typeToRelPropertyMap.TryGetValue(entityType, out relPropertyList)) { relPropertyList = new List <RelProperty>(); typeToRelPropertyMap[entityType] = relPropertyList; } foreach (DbRelatedEntityRef relatedEntityReference in instanceExpression.RelatedEntityReferences) { RelProperty key = new RelProperty((RelationshipType)relatedEntityReference.TargetEnd.DeclaringType, relatedEntityReference.SourceEnd, relatedEntityReference.TargetEnd); DbExpression targetEntityReference = relatedEntityReference.TargetEntityReference; DbExpression y; if (relPropertyMap.TryGetValue(key, out y)) { if (!DiscriminatorMap.ExpressionsCompatible(targetEntityReference, y)) { return(false); } } else { relPropertyMap.Add(key, targetEntityReference); } relPropertyList.Add(key); } } return(true); }
/// <summary> /// Given an extent and its corresponding view, invokes the parser to check if the view definition is syntactically correct. /// Iff parsing succeeds: <paramref name="commandTree" /> and <paramref name="discriminatorMap" /> are set to the parse result and method returns true, /// otherwise if parser has thrown a catchable exception, it is returned via <paramref name="parserException" /> parameter, /// otherwise exception is re-thrown. /// </summary> private static bool TryParseView( string eSQL, bool isUserSpecified, EntitySetBase extent, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config, out DbQueryCommandTree commandTree, out DiscriminatorMap discriminatorMap, out Exception parserException) { commandTree = null; discriminatorMap = null; parserException = null; // We do not catch any internal exceptions any more config.StartSingleWatch(PerfType.ViewParsing); try { // If it is a user specified view, allow all queries. Otherwise parse the view in the restricted mode. var compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (isUserSpecified) { compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode; } Debug.Assert(!String.IsNullOrEmpty(eSQL), "eSQL query is not specified"); commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode); // For non user-specified views, perform simplification. if (!isUserSpecified) { commandTree = ViewSimplifier.SimplifyView(extent, commandTree); } // See if the view matches the "discriminated" pattern (allows simplification of generated store commands) if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } } catch (Exception e) { // Catching all the exception types since Query parser seems to be throwing veriety of // exceptions - EntityException, ArgumentException, ArgumentNullException etc. if (e.IsCatchableExceptionType()) { parserException = e; } else { throw; } } finally { config.StopSingleWatch(PerfType.ViewParsing); } Debug.Assert(commandTree != null || parserException != null, "Either commandTree or parserException is expected."); // Note: m_commandTree might have been initialized by a previous call to this method, so in consequent calls it might occur that // both m_commandTree and parserException are not null - this would mean that the last parse attempt failed, but m_commandTree value is // preserved from the previous call. return parserException == null; }
private GeneratedView( EntitySetBase extent, EdmType type, DbQueryCommandTree commandTree, string eSQL, DiscriminatorMap discriminatorMap, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config) { // At least one of the commandTree or eSQL must be specified. // Both are specified in the case of user-defined views. Debug.Assert(commandTree != null || !String.IsNullOrEmpty(eSQL), "commandTree or eSQL must be specified"); m_extent = extent; m_type = type; m_commandTree = commandTree; m_eSQL = eSQL; m_discriminatorMap = discriminatorMap; m_mappingItemCollection = mappingItemCollection; m_config = config; if (m_config.IsViewTracing) { var trace = new StringBuilder(1024); ToCompactString(trace); Helpers.FormatTraceLine("CQL view for {0}", trace.ToString()); } }
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); 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."); 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; var structuralTypeMappingView = GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable); if (structuralTypeMappingView == null) { continue; } else { structuralTypeMappingViews.Add(structuralTypeMappingView); } } Debug.Assert( structuralTypeMappingViews.Count == structuralTypePredicates.Count, "structuralTypeMappingViews.Count == structuralTypePredicates.Count"); if (structuralTypeMappingViews.Count != m_structuralTypeMappings.Count) { 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(FunctionImport.EntitySet, queryExpression, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } return queryExpression; }
internal DbQueryCommandTree GenerateFunctionView(out DiscriminatorMap discriminatorMap) { DebugCheck.NotNull(m_mappingItemCollection); discriminatorMap = null; // Prepare the direct call of the store function as StoreFunction(@EdmFunc_p1, ..., @EdmFunc_pN). // Note that function call arguments are command parameters created from the m_edmFunction parameters. Debug.Assert(TargetFunction != null, "this.TargetFunction != null"); DbExpression storeFunctionInvoke = TargetFunction.Invoke(GetParametersForTargetFunctionCall()); // Generate the query expression producing c-space result from s-space function call(s). DbExpression queryExpression; if (m_structuralTypeMappings != null) { queryExpression = GenerateStructuralTypeResultMappingView(storeFunctionInvoke, out discriminatorMap); Debug.Assert( queryExpression == null || TypeSemantics.IsPromotableTo(queryExpression.ResultType, FunctionImport.ReturnParameter.TypeUsage), "TypeSemantics.IsPromotableTo(queryExpression.ResultType, this.FunctionImport.ReturnParameter.TypeUsage)"); } else { queryExpression = GenerateScalarResultMappingView(storeFunctionInvoke); Debug.Assert( queryExpression == null || TypeSemantics.IsEqual(queryExpression.ResultType, FunctionImport.ReturnParameter.TypeUsage), "TypeSemantics.IsEqual(queryExpression.ResultType, this.FunctionImport.ReturnParameter.TypeUsage)"); } if (queryExpression == null) { // In case of errors during view generation, return. return null; } // Generate parameterized command, where command parameters are semantically the c-space function parameters. return DbQueryCommandTree.FromValidExpression( m_mappingItemCollection.Workspace, TargetPerspective.TargetPerspectiveDataSpace, queryExpression); }
internal static bool TryCreateDiscriminatorMap( EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap) { discriminatorMap = (DiscriminatorMap)null; if (queryView.ExpressionKind != DbExpressionKind.Project) { return(false); } DbProjectExpression projectExpression = (DbProjectExpression)queryView; if (projectExpression.Projection.ExpressionKind != DbExpressionKind.Case) { return(false); } DbCaseExpression projection = (DbCaseExpression)projectExpression.Projection; if (projectExpression.Projection.ResultType.EdmType.BuiltInTypeKind != BuiltInTypeKind.EntityType || projectExpression.Input.Expression.ExpressionKind != DbExpressionKind.Filter) { return(false); } DbFilterExpression expression1 = (DbFilterExpression)projectExpression.Input.Expression; HashSet <object> discriminatorDomain = new HashSet <object>(); if (!ViewSimplifier.TryMatchDiscriminatorPredicate(expression1, (Action <DbComparisonExpression, object>)((equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue)))) { return(false); } List <KeyValuePair <object, EntityType> > keyValuePairList = new List <KeyValuePair <object, EntityType> >(); Dictionary <EdmProperty, DbExpression> propertyMap = new Dictionary <EdmProperty, DbExpression>(); Dictionary <RelProperty, DbExpression> relPropertyMap = new Dictionary <RelProperty, DbExpression>(); Dictionary <EntityType, List <RelProperty> > typeToRelPropertyMap = new Dictionary <EntityType, List <RelProperty> >(); DbPropertyExpression discriminator = (DbPropertyExpression)null; EdmProperty edmProperty = (EdmProperty)null; for (int index = 0; index < projection.When.Count; ++index) { DbExpression expression2 = projection.When[index]; DbExpression then = projection.Then[index]; string variableName = projectExpression.Input.VariableName; DbPropertyExpression property; object key; if (!ViewSimplifier.TryMatchPropertyEqualsValue(expression2, variableName, out property, out key)) { return(false); } if (edmProperty == null) { edmProperty = (EdmProperty)property.Property; } else if (edmProperty != property.Property) { return(false); } discriminator = property; EntityType entityType; if (!DiscriminatorMap.TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out entityType)) { return(false); } keyValuePairList.Add(new KeyValuePair <object, EntityType>(key, entityType)); discriminatorDomain.Remove(key); } EntityType entityType1; if (1 != discriminatorDomain.Count || projection.Else == null || !DiscriminatorMap.TryMatchEntityTypeConstructor(projection.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out entityType1)) { return(false); } keyValuePairList.Add(new KeyValuePair <object, EntityType>(discriminatorDomain.Single <object>(), entityType1)); if (!DiscriminatorMap.CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap) || keyValuePairList.Select <KeyValuePair <object, EntityType>, object>((Func <KeyValuePair <object, EntityType>, object>)(map => map.Key)).Distinct <object>((IEqualityComparer <object>)TrailingSpaceComparer.Instance).Count <object>() != keyValuePairList.Count) { return(false); } discriminatorMap = new DiscriminatorMap(discriminator, keyValuePairList, propertyMap, relPropertyMap, entitySet); return(true); }