/// <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 FunctionImportNormalizedEntityTypeMapping(FunctionImportStructuralTypeMappingKB parent, List <FunctionImportEntityTypeMappingCondition> columnConditions, BitArray impliedEntityTypes) { // validate arguments EntityUtil.CheckArgumentNull(parent, "parent"); EntityUtil.CheckArgumentNull(columnConditions, "discriminatorValues"); EntityUtil.CheckArgumentNull(impliedEntityTypes, "impliedEntityTypes"); Debug.Assert(columnConditions.Count == parent.DiscriminatorColumns.Count, "discriminator values must be ordinally aligned with discriminator columns"); Debug.Assert(impliedEntityTypes.Count == parent.MappedEntityTypes.Count, "implied entity types must be ordinally aligned with mapped entity types"); this.ColumnConditions = new OM.ReadOnlyCollection <FunctionImportEntityTypeMappingCondition>(columnConditions.ToList()); this.ImpliedEntityTypes = impliedEntityTypes; this.ComplementImpliedEntityTypes = (new BitArray(this.ImpliedEntityTypes)).Not(); }
internal FunctionImportNormalizedEntityTypeMapping( FunctionImportStructuralTypeMappingKB parent, List<FunctionImportEntityTypeMappingCondition> columnConditions, BitArray impliedEntityTypes) { // validate arguments //Contract.Requires(parent != null); //Contract.Requires(columnConditions != null); //Contract.Requires(impliedEntityTypes != null); Debug.Assert( columnConditions.Count == parent.DiscriminatorColumns.Count, "discriminator values must be ordinally aligned with discriminator columns"); Debug.Assert( impliedEntityTypes.Count == parent.MappedEntityTypes.Count, "implied entity types must be ordinally aligned with mapped entity types"); ColumnConditions = new ReadOnlyCollection<FunctionImportEntityTypeMappingCondition>(columnConditions.ToList()); ImpliedEntityTypes = impliedEntityTypes; ComplementImpliedEntityTypes = (new BitArray(ImpliedEntityTypes)).Not(); }
/// <summary> /// Gets the disctriminator columns resultSetIndexth result set, or an empty array if the index is not in range /// </summary> internal IList <string> GetDiscriminatorColumns(int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); return(resultMapping.DiscriminatorColumns); }
/// <summary> /// Given discriminator values (ordinally aligned with DiscriminatorColumns), determines /// the entity type to return. Throws a CommandExecutionException if the type is ambiguous. /// </summary> internal EntityType Discriminate(object[] discriminatorValues, int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); Debug.Assert(resultMapping != null); // initialize matching types bit map BitArray typeCandidates = new BitArray(resultMapping.MappedEntityTypes.Count, true); foreach (var typeMapping in resultMapping.NormalizedEntityTypeMappings) { // check if this type mapping is matched bool matches = true; var columnConditions = typeMapping.ColumnConditions; for (int i = 0; i < columnConditions.Count; i++) { if (null != columnConditions[i] && // this discriminator doesn't matter for the given condition !columnConditions[i].ColumnValueMatchesCondition(discriminatorValues[i])) { matches = false; break; } } if (matches) { // if the type condition is met, narrow the set of type candidates typeCandidates = typeCandidates.And(typeMapping.ImpliedEntityTypes); } else { // if the type condition fails, all implied types are eliminated // (the type mapping fragment is a co-implication, so a type is no longer // a candidate if any condition referring to it is false) typeCandidates = typeCandidates.And(typeMapping.ComplementImpliedEntityTypes); } } // find matching type condition EntityType entityType = null; for (int i = 0; i < typeCandidates.Length; i++) { if (typeCandidates[i]) { if (null != entityType) { throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType); } entityType = resultMapping.MappedEntityTypes[i]; } } // if there is no match, raise an exception if (null == entityType) { throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType); } return(entityType); }