/// <summary> /// Creates a ProviderCommandInfo for the given node. /// This method should be called when the keys, foreign keys and sort keys are known ahead of time. /// Typically it is used when the original command is factored into multiple commands. /// </summary> /// <param name="command">The owning command, used for creating VarVecs, etc</param> /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param> /// <param name="children">A list of ProviderCommandInfos that were created for the child sub-commands.</param> /// <returns>The resulting ProviderCommandInfo</returns> internal static ProviderCommandInfo Create( Command command, Node node, List <ProviderCommandInfo> children) { PhysicalProjectOp projectOp = node.Op as PhysicalProjectOp; PlanCompiler.Assert(projectOp != null, "Expected root Op to be a physical Project"); // build up the CQT DbCommandTree ctree = CTreeGenerator.Generate(command, node); DbQueryCommandTree cqtree = ctree as DbQueryCommandTree; PlanCompiler.Assert(cqtree != null, "null query command tree"); // Get the rowtype for the result cqt md.CollectionType collType = TypeHelpers.GetEdmType <md.CollectionType>(cqtree.Query.ResultType); PlanCompiler.Assert(md.TypeSemantics.IsRowType(collType.TypeUsage), "command rowtype is not a record"); // Build up a mapping from Vars to the corresponding output property/column Dictionary <Var, md.EdmProperty> outputVarMap = BuildOutputVarMap(projectOp, collType.TypeUsage); return(new ProviderCommandInfo(ctree, children)); }
private static bool TryGetCommonType(CollectionType collectionType1, CollectionType collectionType2, out EdmType commonType) { TypeUsage commonTypeUsage = null; if (!TryGetCommonType(collectionType1.TypeUsage, collectionType2.TypeUsage, out commonTypeUsage)) { commonType = null; return false; } commonType = new CollectionType(commonTypeUsage); return true; }
private DbExpression RewriteCollection(DbExpression expression, CollectionType collectionType) { DbExpression 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 (this.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) { this.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). this.EnterCollection(); } // If the expression is already a DbProjectExpression then simply visit the projection, // instead of introducing another projection over the existing one. DbExpression result = expression; if (project != null) { DbExpression newProjection = this.Rewrite(project.Projection); if (!object.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. DbExpressionBinding collectionBinding = target.BindAs(_aliasGenerator.Next()); DbExpression projection = collectionBinding.Variable; DbExpression spannedProjection = this.Rewrite(projection); if (!object.ReferenceEquals(projection, spannedProjection)) { result = collectionBinding.Project(spannedProjection); } } // Remove any navigation information from scope, if it was added this.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. List<DbVariableReferenceExpression> formals = new List<DbVariableReferenceExpression>(1); formals.Add(navInfo.SourceVariable); List<DbExpression> args = new List<DbExpression>(1); args.Add(navInfo.Source); result = DbExpressionBuilder.Invoke(DbExpressionBuilder.Lambda(result, formals), args); } // Return the (possibly rewritten) collection expression. return result; }
/// <summary> /// Returns a Model type usage for a provider type /// </summary> /// <returns>model (CSpace) type usage</returns> internal TypeUsage GetModelTypeUsage() { if (_modelTypeUsage == null) { EdmType edmType = this.EdmType; // If the edm type is already a cspace type, return the same type if (edmType.DataSpace == DataSpace.CSpace || edmType.DataSpace == DataSpace.OSpace) { return(this); } TypeUsage result; if (Helper.IsRowType(edmType)) { RowType sspaceRowType = (RowType)edmType; EdmProperty[] properties = new EdmProperty[sspaceRowType.Properties.Count]; for (int i = 0; i < properties.Length; i++) { EdmProperty sspaceProperty = sspaceRowType.Properties[i]; TypeUsage newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage(); properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage); } RowType edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata); result = TypeUsage.Create(edmRowType, this.Facets); } else if (Helper.IsCollectionType(edmType)) { CollectionType sspaceCollectionType = ((CollectionType)edmType); TypeUsage newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage(); result = TypeUsage.Create(new CollectionType(newTypeUsage), this.Facets); } else if (Helper.IsRefType(edmType)) { System.Diagnostics.Debug.Assert(((RefType)edmType).ElementType.DataSpace == DataSpace.CSpace); result = this; } else if (Helper.IsPrimitiveType(edmType)) { result = ((PrimitiveType)edmType).ProviderManifest.GetEdmType(this); if (result == null) { throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Mapping_ProviderReturnsNullType(this.ToString())); } if (!TypeSemantics.IsNullable(this)) { result = TypeUsage.Create(result.EdmType, OverrideFacetValues(result.Facets, new FacetValues { Nullable = false })); } } else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType)) { result = this; } else { System.Diagnostics.Debug.Assert(false, "Unexpected type found in entity data reader"); return(null); } System.Threading.Interlocked.CompareExchange(ref _modelTypeUsage, result, null); } return(_modelTypeUsage); }
// Generates and caches a command definition for the given function internal DbCommandDefinition GenerateCommandDefinition(StorageModificationFunctionMapping functionMapping) { if (null == m_modificationFunctionCommandDefinitions) { m_modificationFunctionCommandDefinitions = new Dictionary<StorageModificationFunctionMapping,DbCommandDefinition>(); } DbCommandDefinition commandDefinition; if (!m_modificationFunctionCommandDefinitions.TryGetValue(functionMapping, out commandDefinition)) { // synthesize a RowType for this mapping TypeUsage resultType = null; if (null != functionMapping.ResultBindings && 0 < functionMapping.ResultBindings.Count) { List<EdmProperty> properties = new List<EdmProperty>(functionMapping.ResultBindings.Count); foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings) { properties.Add(new EdmProperty(resultBinding.ColumnName, resultBinding.Property.TypeUsage)); } RowType rowType = new RowType(properties); CollectionType collectionType = new CollectionType(rowType); resultType = TypeUsage.Create(collectionType); } // add function parameters IEnumerable<KeyValuePair<string, TypeUsage>> functionParams = functionMapping.Function.Parameters.Select(paramInfo => new KeyValuePair<string, TypeUsage>(paramInfo.Name, paramInfo.TypeUsage)); // construct DbFunctionCommandTree including implict return type DbFunctionCommandTree tree = new DbFunctionCommandTree(m_metadataWorkspace, DataSpace.SSpace, functionMapping.Function, resultType, functionParams); commandDefinition = m_providerServices.CreateCommandDefinition(tree); } return commandDefinition; }
internal override TypeUsage GetTypeUsage() { if (_typeUsage != null) { return _typeUsage; } Debug.Assert(_typeSubElement != null, "For attributes typeusage should have been resolved"); if (_typeSubElement != null) { CollectionType collectionType = new CollectionType(_typeSubElement.GetTypeUsage()); collectionType.AddMetadataProperties(this.OtherContent); _typeUsage = TypeUsage.Create(collectionType); } return _typeUsage; }
protected override void Visit(CollectionType collectionType) { int index; if (!this.AddObjectToSeenListAndHashBuilder(collectionType, out index)) { return; } this.AddObjectStartDumpToHashBuilder(collectionType, index); #region Inner data visit this.AddObjectContentToHashBuilder(collectionType.Identity); // Identity contains Name, NamespaceName and FullName base.Visit(collectionType); #endregion this.AddObjectEndDumpToHashBuilder(); }
protected virtual void Visit(CollectionType collectionType) { Visit(collectionType.BaseType); Visit(collectionType.TypeUsage); }
/// <summary>Convert CSpace TypeMetadata into OSpace TypeMetadata</summary> /// <param name="clrType"></param> /// <returns>OSpace type metadata</returns> private EdmType ConvertOSpaceToCSpaceType(EdmType clrType) { EdmType cdmType = null; if (Helper.IsCollectionType(clrType)) { EdmType elemType = ConvertOSpaceToCSpaceType(((CollectionType)clrType).TypeUsage.EdmType); cdmType = new CollectionType(elemType); } else if (Helper.IsRowType(clrType)) { List<EdmProperty> cdmProperties = new List<EdmProperty>(); foreach (EdmProperty column in ((RowType)clrType).Properties) { EdmType cdmPropertyType = ConvertOSpaceToCSpaceType(column.TypeUsage.EdmType); EdmProperty cdmPorperty = new EdmProperty(column.Name, TypeUsage.Create(cdmPropertyType)); cdmProperties.Add(cdmPorperty); } cdmType = new RowType(cdmProperties, ((RowType)clrType).InitializerMetadata); } else if (Helper.IsRefType(clrType)) { cdmType = new RefType((EntityType)(ConvertOSpaceToCSpaceType(((RefType)clrType).ElementType))); } else { cdmType = ((ObjectTypeMapping)GetMap(clrType)).EdmType; } Debug.Assert((null != cdmType), "null converted clr type"); return cdmType; }
/// <summary>Convert CSpace TypeMetadata into OSpace TypeMetadata</summary> /// <param name="cdmType"></param> /// <returns>OSpace type metadata</returns> private EdmType ConvertCSpaceToOSpaceType(EdmType cdmType) { EdmType clrType = null; if (Helper.IsCollectionType(cdmType)) { var elemType = ConvertCSpaceToOSpaceType(((CollectionType)cdmType).TypeUsage.EdmType); clrType = new CollectionType(elemType); } else if (Helper.IsRowType(cdmType)) { var clrProperties = new List<EdmProperty>(); var rowType = (RowType)cdmType; foreach (var column in rowType.Properties) { var clrPropertyType = ConvertCSpaceToOSpaceType(column.TypeUsage.EdmType); var clrProperty = new EdmProperty(column.Name, TypeUsage.Create(clrPropertyType)); clrProperties.Add(clrProperty); } clrType = new RowType(clrProperties, rowType.InitializerMetadata); } else if (Helper.IsRefType(cdmType)) { clrType = new RefType((EntityType)ConvertCSpaceToOSpaceType(((RefType)cdmType).ElementType)); } else if (Helper.IsPrimitiveType(cdmType)) { clrType = m_objectCollection.GetMappedPrimitiveType(((PrimitiveType)cdmType).PrimitiveTypeKind); } else { clrType = ((ObjectTypeMapping)GetMap(cdmType)).ClrType; } Debug.Assert((null != clrType), "null converted clr type"); return clrType; }
/// <summary> /// Main code generator method. /// </summary> /// <param name="namespaceString">Namespace where the class will reside</param> /// <param name="className">Generated class name</param> /// <param name="attributeNamespace">The 'EdmFunction' attribute parameter</param> /// <param name="pascalCaseFunctionNames">If the input function names need to be pascal cased.</param> public StringWriter GenerateCode(string namespaceString, string className, string attributeNamespace, Boolean pascalCaseFunctionNames) { StringWriter newCode = new StringWriter(); Boolean isAggregateFunction; bool hasSByteParameterOrReturnType; bool hasStringInParameterName; String separator; GenerateFileHeader(newCode, className); GenerateUsingStatements(newCode); newCode.WriteLine("namespace " + namespaceString); newCode.WriteLine("{"); GenerateClassHeader(newCode, className, attributeNamespace); foreach (System.Data.Metadata.Edm.EdmFunction function in _functions) { isAggregateFunction = false; hasSByteParameterOrReturnType = false; hasStringInParameterName = false; separator = ""; String functionNameToUse = FindCorrectFunctionName(function.Name, pascalCaseFunctionNames); GenerateFunctionHeader(newCode, attributeNamespace, function.Name); Type returnType = ((PrimitiveType)(function.ReturnParameter.TypeUsage.EdmType)).ClrEquivalentType; //Suppress warning that 'SByte' is not CLS-compliant. if (returnType == typeof(SByte)) { hasSByteParameterOrReturnType = true; } StringBuilder functionSignatureString = new StringBuilder(); AppendSpaces(functionSignatureString, 8); functionSignatureString.Append("public static "); WriteType(functionSignatureString, returnType); functionSignatureString.Append(functionNameToUse + "("); ReadOnlyMetadataCollection <FunctionParameter> functionParameters = function.Parameters; Type parameterType; foreach (System.Data.Metadata.Edm.FunctionParameter parameter in functionParameters) { String parameterNameToUse = parameter.Name; parameterNameToUse = FindCorrectParameterName(parameterNameToUse); //Detect aggregate functions. They have just one parameter and so stub can be generated here. if (parameter.TypeUsage.EdmType.GetType() == typeof(System.Data.Metadata.Edm.CollectionType)) { isAggregateFunction = true; if (parameterNameToUse.ToLowerInvariant().Contains("string")) { hasStringInParameterName = true; } System.Data.Metadata.Edm.CollectionType collectionType = (System.Data.Metadata.Edm.CollectionType)parameter.TypeUsage.EdmType; parameterType = ((PrimitiveType)(collectionType.TypeUsage.EdmType)).ClrEquivalentType; //Detect if there is an 'SByte' parameter to suppress non-CLS-compliance warning. //Generate the attribute only once for each function. if (parameterType == typeof(SByte)) { hasSByteParameterOrReturnType = true; } //Generate stub for non-nullable input parameters functionSignatureString.Append("IEnumerable<" + parameterType.ToString()); //Supress fxcop message and CLS non-compliant attributes GenerateFunctionAttributes(newCode, hasStringInParameterName, hasSByteParameterOrReturnType); //Use the constructed function signature newCode.Write(functionSignatureString.ToString()); GenerateAggregateFunctionStub(newCode, parameterType, returnType, parameterNameToUse, false); //Generate stub for nullable input parameters //Special Case: Do not generate nullable stub for input parameter of types Byte[] //and String, since they are nullable. if (!IsNullableType(parameterType)) { GenerateFunctionHeader(newCode, attributeNamespace, function.Name); //Supress fxcop message and CLS non-compliant attributes GenerateFunctionAttributes(newCode, hasStringInParameterName, hasSByteParameterOrReturnType); //Use the constructed function signature newCode.Write(functionSignatureString.ToString()); GenerateAggregateFunctionStub(newCode, parameterType, returnType, parameterNameToUse, true); } } //End of processing parameters for aggregate functions. //Process each parameter in case of non-aggregate functions. else { parameterType = ((PrimitiveType)(parameter.TypeUsage.EdmType)).ClrEquivalentType; functionSignatureString.Append(separator); WriteType(functionSignatureString, parameterType); functionSignatureString.Append(parameterNameToUse); separator = ", "; //Detect if there is an 'SByte' parameter to suppress non-CLS-compliance warning. if (parameterType == typeof(SByte)) { hasSByteParameterOrReturnType = true; } if (parameterNameToUse.ToLowerInvariant().Contains("string")) { hasStringInParameterName = true; } } } //End for each parameter //Generate stub for Non-aggregate functions after all input parameters are found. if (!isAggregateFunction) { //Supress fxcop supression and CLS non-compliant attributes GenerateFunctionAttributes(newCode, hasStringInParameterName, hasSByteParameterOrReturnType); newCode.WriteLine(functionSignatureString.ToString() + ")"); AppendSpaces(newCode, 8); newCode.WriteLine("{"); WriteExceptionStatement(newCode); } } //End for each function AppendSpaces(newCode, 4); newCode.WriteLine("}"); newCode.WriteLine("}"); newCode.Close(); return(newCode); }