/// <summary> /// Determines the expected shape of store results. We expect a column for every property /// of the mapped type (or types) and a column for every discriminator column. We make no /// assumptions about the order of columns: the provider is expected to determine appropriate /// types by looking at the names of the result columns, not the order of columns, which is /// different from the typical handling of row types in the EF. /// </summary> /// <remarks> /// Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL /// function. /// </remarks> /// <returns>Row type.</returns> internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace, int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); // Collect all columns as name-type pairs. Dictionary <string, TypeUsage> columns = new Dictionary <string, TypeUsage>(); // Figure out which entity types we expect to yield from the function. IEnumerable <StructuralType> structuralTypes; if (0 == resultMapping.NormalizedEntityTypeMappings.Count) { // No explicit type mappings; just use the type specified in the ReturnType attribute on the function. StructuralType structuralType; MetadataHelper.TryGetFunctionImportReturnType <StructuralType>(this.FunctionImport, resultSetIndex, out structuralType); Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); structuralTypes = new StructuralType[] { structuralType }; } else { // Types are explicitly mapped. structuralTypes = resultMapping.MappedEntityTypes.Cast <StructuralType>(); } // Gather columns corresponding to all properties. foreach (StructuralType structuralType in structuralTypes) { foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // NOTE: if a complex type is encountered, the column map generator will // throw. For now, we just let them through. // We expect to see each property multiple times, so we use indexer rather than // .Add. columns[property.Name] = property.TypeUsage; } } // Gather discriminator columns. foreach (string discriminatorColumn in this.GetDiscriminatorColumns(resultSetIndex)) { if (!columns.ContainsKey(discriminatorColumn)) { // TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); columns.Add(discriminatorColumn, type); } } // Expected type is a collection of rows RowType rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); TypeUsage result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType))); return(result); }
internal TypeUsage GetExpectedTargetResultType(int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); Dictionary <string, TypeUsage> source = new Dictionary <string, TypeUsage>(); IEnumerable <StructuralType> structuralTypes; if (resultMapping.NormalizedEntityTypeMappings.Count == 0) { StructuralType returnType; MetadataHelper.TryGetFunctionImportReturnType <StructuralType>(this.FunctionImport, resultSetIndex, out returnType); structuralTypes = (IEnumerable <StructuralType>) new StructuralType[1] { returnType }; } else { structuralTypes = resultMapping.MappedEntityTypes.Cast <StructuralType>(); } foreach (EdmType edmType in structuralTypes) { foreach (EdmProperty structuralMember in (IEnumerable)TypeHelpers.GetAllStructuralMembers(edmType)) { source[structuralMember.Name] = structuralMember.TypeUsage; } } foreach (string discriminatorColumn in (IEnumerable <string>) this.GetDiscriminatorColumns(resultSetIndex)) { if (!source.ContainsKey(discriminatorColumn)) { TypeUsage stringTypeUsage = TypeUsage.CreateStringTypeUsage(MetadataWorkspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); source.Add(discriminatorColumn, stringTypeUsage); } } return(TypeUsage.Create((EdmType) new CollectionType(TypeUsage.Create((EdmType) new RowType(source.Select <KeyValuePair <string, TypeUsage>, EdmProperty>((Func <KeyValuePair <string, TypeUsage>, EdmProperty>)(c => new EdmProperty(c.Key, c.Value)))))))); }
// <summary> // Determines the expected shape of store results. We expect a column for every property // of the mapped type (or types) and a column for every discriminator column. We make no // assumptions about the order of columns: the provider is expected to determine appropriate // types by looking at the names of the result columns, not the order of columns, which is // different from the typical handling of row types in the EF. // </summary> // <remarks> // Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL // function. // </remarks> // <returns> Row type. </returns> internal TypeUsage GetExpectedTargetResultType(int resultSetIndex) { var resultMapping = GetResultMapping(resultSetIndex); // Collect all columns as name-type pairs. var columns = new Dictionary <string, TypeUsage>(); // Figure out which entity types we expect to yield from the function. IEnumerable <StructuralType> structuralTypes; if (0 == resultMapping.NormalizedEntityTypeMappings.Count) { // No explicit type mappings; just use the type specified in the ReturnType attribute on the function. StructuralType structuralType; MetadataHelper.TryGetFunctionImportReturnType(FunctionImport, resultSetIndex, out structuralType); Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); structuralTypes = new[] { structuralType }; } else { // Types are explicitly mapped. structuralTypes = resultMapping.MappedEntityTypes.Cast <StructuralType>(); } // Gather columns corresponding to all properties. foreach (var structuralType in structuralTypes) { foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // NOTE: if a complex type is encountered, the column map generator will // throw. For now, we just let them through. // We expect to see each property multiple times, so we use indexer rather than // .Add. columns[property.Name] = property.TypeUsage; } } // Gather discriminator columns. foreach (var discriminatorColumn in GetDiscriminatorColumns(resultSetIndex)) { if (!columns.ContainsKey(discriminatorColumn)) { // CONSIDER: we assume that discriminatorColumns are all string types. In practice, // we're flexible about the runtime type during materialization, so the provider's // decision is hopefully irrelevant. The alternative is to require typed stored // procedure declarations in the SSDL, which is too much of a burden on the user and/or the // tools (there is no reliable way of determining this metadata automatically from SQL // Server). var type = TypeUsage.CreateStringTypeUsage( MetadataWorkspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); columns.Add(discriminatorColumn, type); } } // Expected type is a collection of rows var rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); var result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType))); return(result); }
/// <summary> /// Determines the expected shape of store results. We expect a column for every property /// of the mapped type (or types) and a column for every discriminator column. We make no /// assumptions about the order of columns: the provider is expected to determine appropriate /// types by looking at the names of the result columns, not the order of columns, which is /// different from the typical handling of row types in the EF. /// </summary> /// <remarks> /// Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL /// function. /// </remarks> /// <returns>Row type.</returns> internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace, int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); // Collect all columns as name-type pairs. Dictionary<string, TypeUsage> columns = new Dictionary<string, TypeUsage>(); // Figure out which entity types we expect to yield from the function. IEnumerable<StructuralType> structuralTypes; if (0 == resultMapping.NormalizedEntityTypeMappings.Count) { // No explicit type mappings; just use the type specified in the ReturnType attribute on the function. StructuralType structuralType; MetadataHelper.TryGetFunctionImportReturnType<StructuralType>(this.FunctionImport, resultSetIndex, out structuralType); Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); structuralTypes = new StructuralType[] { structuralType }; } else { // Types are explicitly mapped. structuralTypes = resultMapping.MappedEntityTypes.Cast<StructuralType>(); } // Gather columns corresponding to all properties. foreach (StructuralType structuralType in structuralTypes) { foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // NOTE: if a complex type is encountered, the column map generator will // throw. For now, we just let them through. // We expect to see each property multiple times, so we use indexer rather than // .Add. columns[property.Name] = property.TypeUsage; } } // Gather discriminator columns. foreach (string discriminatorColumn in this.GetDiscriminatorColumns(resultSetIndex)) { if (!columns.ContainsKey(discriminatorColumn)) { // TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); columns.Add(discriminatorColumn, type); } } // Expected type is a collection of rows RowType rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); TypeUsage result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType))); return result; }
private static bool TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type) { type = (TypeUsage)null; type = modelType != PrimitiveTypeKind.String ? MetadataWorkspace.GetCanonicalModelTypeUsage(modelType) : TypeUsage.CreateStringTypeUsage(MetadataWorkspace.GetModelPrimitiveType(modelType), false, false); return(null != type); }