/// <summary>
        ///     Creates a column map for the given reader and function mapping.
        /// </summary>
        internal virtual CollectionColumnMap CreateFunctionImportStructuralTypeColumnMap(
            DbDataReader storeDataReader, FunctionImportMappingNonComposable mapping, int resultSetIndex, EntitySet entitySet,
            StructuralType baseStructuralType)
        {
            var resultMapping = mapping.GetResultMapping(resultSetIndex);
            Debug.Assert(resultMapping != null);
            if (resultMapping.NormalizedEntityTypeMappings.Count == 0) // no explicit mapping; use default non-polymorphic reader
            {
                // if there is no mapping, create default mapping to root entity type or complex type
                Debug.Assert(!baseStructuralType.Abstract, "mapping loader must verify abstract types have explicit mapping");

                return CreateColumnMapFromReaderAndType(
                    storeDataReader, baseStructuralType, entitySet, resultMapping.ReturnTypeColumnsRenameMapping);
            }

            // the section below deals with the polymorphic entity type mapping for return type
            var baseEntityType = baseStructuralType as EntityType;
            Debug.Assert(null != baseEntityType, "We should have entity type here");

            // Generate column maps for all discriminators
            var discriminatorColumns = CreateDiscriminatorColumnMaps(storeDataReader, mapping, resultSetIndex);

            // Generate default maps for all mapped entity types
            var mappedEntityTypes = new HashSet<EntityType>(resultMapping.MappedEntityTypes);
            mappedEntityTypes.Add(baseEntityType); // make sure the base type is represented
            var typeChoices = new Dictionary<EntityType, TypedColumnMap>(mappedEntityTypes.Count);
            ColumnMap[] baseTypeColumnMaps = null;
            foreach (var entityType in mappedEntityTypes)
            {
                var propertyColumnMaps = GetColumnMapsForType(storeDataReader, entityType, resultMapping.ReturnTypeColumnsRenameMapping);
                var entityColumnMap = CreateEntityTypeElementColumnMap(
                    storeDataReader, entityType, entitySet, propertyColumnMaps, resultMapping.ReturnTypeColumnsRenameMapping);
                if (!entityType.Abstract)
                {
                    typeChoices.Add(entityType, entityColumnMap);
                }
                if (entityType == baseStructuralType)
                {
                    baseTypeColumnMaps = propertyColumnMaps;
                }
            }

            // NOTE: We don't have a null sentinel here, because the stored proc won't 
            //       return one anyway; we'll just presume the data's always there.
            var polymorphicMap = new MultipleDiscriminatorPolymorphicColumnMap(
                TypeUsage.Create(baseStructuralType), baseStructuralType.Name, baseTypeColumnMaps, discriminatorColumns, typeChoices,
                (object[] discriminatorValues) => mapping.Discriminate(discriminatorValues, resultSetIndex));
            CollectionColumnMap collection = new SimpleCollectionColumnMap(
                baseStructuralType.GetCollectionType().TypeUsage, baseStructuralType.Name, polymorphicMap, null, null);
            return collection;
        }
        private static void SetupFooFunction(MetadataWorkspace metadataWorkspace)
        {
            var metadataWorkspaceMock = Mock.Get(metadataWorkspace);
            var entityType = (EdmType)new EntityType(
                                          "ReturnedEntity", "FooNamespace", DataSpace.CSpace,
                                          new[] { "key" }, new EdmMember[] { new EdmProperty("key") });
            var collectionTypeMock = new Mock<CollectionType>(entityType)
            {
                CallBase = true
            };
            metadataWorkspaceMock.Setup(m => m.TryDetermineCSpaceModelType(It.IsAny<Type>(), out entityType))
                                 .Returns(true);

            var entityContainer = new EntityContainer("Bar", DataSpace.CSpace);
            metadataWorkspaceMock.Setup(m => m.TryGetEntityContainer(It.IsAny<string>(), It.IsAny<DataSpace>(), out entityContainer))
                                 .Returns(true);
            var functionImport = new EdmFunction(
                "Foo", "Bar", DataSpace.CSpace,
                new EdmFunctionPayload
                {
                    IsComposable = false,
                    IsFunctionImport = true,
                    ReturnParameters = new[]
                                {
                                    new FunctionParameter(
                                        EdmConstants.ReturnType,
                                        TypeUsage.Create(collectionTypeMock.Object),
                                        ParameterMode.ReturnValue),
                                }
                });
            entityContainer.AddFunctionImport(functionImport);

            entityContainer.AddEntitySetBase(new EntitySet("Foo", "", "", "", (EntityType)entityType));

            var edmItemCollection = (EdmItemCollection)metadataWorkspace.GetItemCollection(DataSpace.CSpace);
            var storeItemCollection = (StoreItemCollection)metadataWorkspace.GetItemCollection(DataSpace.SSpace);
            var containerMappingMock = new Mock<EntityContainerMapping>(entityContainer);
            FunctionImportMapping targetFunctionMapping = new FunctionImportMappingNonComposable(
                functionImport, functionImport, new List<List<FunctionImportStructuralTypeMapping>>(), edmItemCollection);
            containerMappingMock.Setup(
                m => m.TryGetFunctionImportMapping(
                    It.IsAny<EdmFunction>(), out targetFunctionMapping)).Returns(true);

            var storageMappingItemCollection = new Mock<StorageMappingItemCollection>(
                edmItemCollection, storeItemCollection, new string[0])
            {
                CallBase = true
            };
            storageMappingItemCollection.Setup(m => m.GetItems<EntityContainerMapping>())
                                        .Returns(
                                            new ReadOnlyCollection<EntityContainerMapping>(
                                                new List<EntityContainerMapping>
                                                        {
                                                            containerMappingMock.Object
                                                        }));

            metadataWorkspaceMock.Setup(m => m.GetItemCollection(DataSpace.CSSpace, It.IsAny<bool>()))
                                 .Returns(storageMappingItemCollection.Object);
        }
        public static void AddFunction(
            this DbModel model,
            MethodInfo methodInfo,
            FunctionAttribute functionAttribute)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            if (methodInfo == null)
            {
                throw new ArgumentNullException(nameof(methodInfo));
            }

            if (functionAttribute == null)
            {
                throw new ArgumentNullException(nameof(functionAttribute));
            }

            /*
    <!-- SSDL content -->
    <edmx:StorageModels>
      <Schema Namespace="CodeFirstDatabaseSchema" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">
        <Function Name="ufnGetContactInformation" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
          <Parameter Name="PersonID" Type="int" Mode="In" />
          <ReturnType>
            <CollectionType>
              <RowType>
                <Property Name="PersonID" Type="int" Nullable="false" />
                <Property Name="FirstName" Type="nvarchar" MaxLength="50" />
                <Property Name="LastName" Type="nvarchar" MaxLength="50" />
                <Property Name="JobTitle" Type="nvarchar" MaxLength="50" />
                <Property Name="BusinessEntityType" Type="nvarchar" MaxLength="50" />
              </RowType>
            </CollectionType>
          </ReturnType>
        </Function>
        <Function Name="ufnGetProductListPrice" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="money">
          <Parameter Name="ProductID" Type="int" Mode="In" />
          <Parameter Name="OrderDate" Type="datetime" Mode="In" />
        </Function>
        <Function Name="ufnGetProductStandardCost" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
          <Parameter Name="ProductID" Type="int" Mode="In" />
          <Parameter Name="OrderDate" Type="datetime" Mode="In" />
          <CommandText>
            SELECT [dbo].[ufnGetProductListPrice](@ProductID, @OrderDate)
          </CommandText>
        </Function>
        <Function Name="uspGetCategoryAndSubCategory" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
          <Parameter Name="CategoryID" Type="int" Mode="In" />
        </Function>
        <Function Name="uspGetManagerEmployees" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
          <Parameter Name="BusinessEntityID" Type="int" Mode="In" />
        </Function>
        <EntityContainer Name="CodeFirstDatabase">
        </EntityContainer>
      </Schema>
    </edmx:StorageModels>
            */
            // Build above <StorageModels> imperatively.
            string functionName = functionAttribute.FunctionName;
            if (string.IsNullOrWhiteSpace(functionName))
            {
                functionName = methodInfo.Name;
            }

            EdmFunction storeFunction = EdmFunction.Create(
                functionName,
                CodeFirstDatabaseSchema, // model.StoreModel.Container.Name is "CodeFirstDatabase".
                DataSpace.SSpace, // <edmx:StorageModels>
                new EdmFunctionPayload()
                {
                    Schema = functionAttribute.Schema,
                    IsAggregate = functionAttribute.IsAggregate,
                    IsBuiltIn = functionAttribute.IsBuiltIn,
                    IsNiladic = functionAttribute.IsNiladic,
                    IsComposable = functionAttribute.IsComposable,
                    ParameterTypeSemantics = functionAttribute.ParameterTypeSemantics,
                    Parameters = model.GetStoreParameters(methodInfo, functionAttribute),
                    ReturnParameters = model.GetStoreReturnParameters(methodInfo, functionAttribute),
                    CommandText = methodInfo.GetStoreCommandText(functionAttribute, functionName)
                },
                null);
            model.StoreModel.AddItem(storeFunction);

            switch (functionAttribute.Type)
            {
                // Aggregate/Built in/Niladic/Composable scalar-valued function has no <FunctionImport> or <FunctionImportMapping>.
                case FunctionType.ComposableScalarValuedFunction:
                case FunctionType.AggregateFunction:
                case FunctionType.BuiltInFunction:
                case FunctionType.NiladicFunction:
                    return;
            }

            /*
    <!-- CSDL content -->
    <edmx:ConceptualModels>
      <Schema Namespace="AdventureWorks" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
        <EntityContainer Name="AdventureWorks" annotation:LazyLoadingEnabled="true">
          <FunctionImport Name="ufnGetContactInformation" IsComposable="true" ReturnType="Collection(AdventureWorks.ContactInformation)">
            <Parameter Name="PersonID" Mode="In" Type="Int32" />
          </FunctionImport>
          <FunctionImport Name="uspGetCategoryAndSubCategory" ReturnType="Collection(AdventureWorks.CategoryAndSubCategory)">
            <Parameter Name="CategoryID" Mode="In" Type="Int32" />
          </FunctionImport>
          <FunctionImport Name="uspGetManagerEmployees" ReturnType="Collection(AdventureWorks.ManagerEmployee)">
            <Parameter Name="BusinessEntityID" Mode="In" Type="Int32" />
          </FunctionImport>
          <FunctionImport Name="ufnGetProductStandardCost" ReturnType="Collection(Decimal)">
            <Parameter Name="ProductID" Mode="In" Type="Int32" />
            <Parameter Name="OrderDate" Mode="In" Type="DateTime" />
          </FunctionImport>
        </EntityContainer>
      </Schema>
    </edmx:ConceptualModels>
            */
            // Build above <ConceptualModels> imperatively.
            EdmFunction modelFunction = EdmFunction.Create(
                storeFunction.Name,
                model.ConceptualModel.Container.Name,
                DataSpace.CSpace, // <edmx:ConceptualModels>
                new EdmFunctionPayload
                {
                    IsFunctionImport = true,
                    IsComposable = storeFunction.IsComposableAttribute,
                    Parameters = model.GetModelParameters(methodInfo, storeFunction),
                    ReturnParameters = model.GetModelReturnParameters(methodInfo, functionAttribute),
                    EntitySets = model.GetModelEntitySets(methodInfo, functionAttribute)
                },
                null);
            model.ConceptualModel.Container.AddFunctionImport(modelFunction);

            /*
    <!-- C-S mapping content -->
    <edmx:Mappings>
      <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
        <EntityContainerMapping StorageEntityContainer="CodeFirstDatabase" CdmEntityContainer="AdventureWorks">
          <FunctionImportMapping FunctionImportName="ufnGetContactInformation" FunctionName="AdventureWorks.ufnGetContactInformation">
            <ResultMapping>
              <ComplexTypeMapping TypeName="AdventureWorks.ContactInformation">
                <ScalarProperty Name="PersonID" ColumnName="PersonID" />
                <ScalarProperty Name="FirstName" ColumnName="FirstName" />
                <ScalarProperty Name="LastName" ColumnName="LastName" />
                <ScalarProperty Name="JobTitle" ColumnName="JobTitle" />
                <ScalarProperty Name="BusinessEntityType" ColumnName="BusinessEntityType" />
              </ComplexTypeMapping>
            </ResultMapping>
          </FunctionImportMapping>
          <FunctionImportMapping FunctionImportName="uspGetCategoryAndSubCategory" FunctionName="AdventureWorks.uspGetCategoryAndSubCategory">
            <ResultMapping>
              <ComplexTypeMapping TypeName="AdventureWorks.CategoryAndSubCategory">
                <ScalarProperty Name="ProductCategoryID" ColumnName="ProductCategoryID" />
                <ScalarProperty Name="Name" ColumnName="Name" />
              </ComplexTypeMapping>
            </ResultMapping>
          </FunctionImportMapping>
          <FunctionImportMapping FunctionImportName="uspGetManagerEmployees" FunctionName="AdventureWorks.uspGetManagerEmployees">
            <ResultMapping>
              <ComplexTypeMapping TypeName="AdventureWorks.ManagerEmployee">
                <ScalarProperty Name="RecursionLevel" ColumnName="RecursionLevel" />
                <ScalarProperty Name="OrganizationNode" ColumnName="OrganizationNode" />
                <ScalarProperty Name="ManagerFirstName" ColumnName="ManagerFirstName" />
                <ScalarProperty Name="ManagerLastName" ColumnName="ManagerLastName" />
                <ScalarProperty Name="BusinessEntityID" ColumnName="BusinessEntityID" />
                <ScalarProperty Name="FirstName" ColumnName="FirstName" />
                <ScalarProperty Name="LastName" ColumnName="LastName" />
              </ComplexTypeMapping>
            </ResultMapping>
          </FunctionImportMapping>
          <FunctionImportMapping FunctionImportName="ufnGetProductStandardCost" FunctionName="AdventureWorks.ufnGetProductStandardCost" />
        </EntityContainerMapping>
      </Mapping>
    </edmx:Mappings>
            */
            // Build above <Mappings> imperatively.
            FunctionImportMapping mapping;
            if (modelFunction.IsComposableAttribute)
            {
                mapping = new FunctionImportMappingComposable(
                    modelFunction,
                    storeFunction,
                    new FunctionImportResultMapping(),
                    model.ConceptualToStoreMapping);
            }
            else
            {
                mapping = new FunctionImportMappingNonComposable(
                    modelFunction,
                    storeFunction,
                    Enumerable.Empty<FunctionImportResultMapping>(),
                    model.ConceptualToStoreMapping);
            }

            model.ConceptualToStoreMapping.AddFunctionImportMapping(mapping);
        }
        public void WriteFunctionImportMappingElement_writes_result_mapping_for_non_composable_functions_mapped_explicitly_to_EntityType()
        {
            var typeUsage =
                TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32));

            var entityTypeProperty1 = new EdmProperty("ETProperty1", typeUsage);
            var entityTypeProperty2 = new EdmProperty("ETProperty2", typeUsage);

            var entityType = new EntityType("ET", "Ns", DataSpace.CSpace);
            entityType.AddMember(entityTypeProperty1);
            entityType.AddMember(entityTypeProperty2);

            var functionImport =
                new EdmFunction(
                    "f_c", "Ns", DataSpace.CSpace,
                    new EdmFunctionPayload
                    {
                        IsComposable = false,
                        IsFunctionImport = true,
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "ReturnValue",
                                            TypeUsage.CreateDefaultTypeUsage(entityType.GetCollectionType()),
                                            ParameterMode.ReturnValue)
                                    },
                    });

            typeUsage = ProviderRegistry.Sql2008_ProviderManifest.GetStoreType(typeUsage);
            var rowTypeProperty1 = new EdmProperty("RTProperty1", typeUsage);
            var rowTypeProperty2 = new EdmProperty("RTProperty2", typeUsage);
            var rowType = new RowType(new[] { rowTypeProperty1, rowTypeProperty2 });

            var storeFunction =
                new EdmFunction(
                    "f_s", "Ns.Store", DataSpace.SSpace,
                    new EdmFunctionPayload
                    {
                        IsComposable = false,
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "Return",
                                            TypeUsage.CreateDefaultTypeUsage(rowType),
                                            ParameterMode.ReturnValue)
                                    },
                    });

            var functionImportResultMapping = new FunctionImportResultMapping();
            functionImportResultMapping.AddTypeMapping(
                new FunctionImportEntityTypeMapping(
                    new EntityType[0],
                    new [] { entityType },
                    new Collections.ObjectModel.Collection<FunctionImportReturnTypePropertyMapping>()
                    {
                        new FunctionImportReturnTypeScalarPropertyMapping("ETProperty1", "RTProperty1"),
                        new FunctionImportReturnTypeScalarPropertyMapping("ETProperty2", "RTProperty2")
                    },
                    new FunctionImportEntityTypeMappingCondition[]
                    {
                        new FunctionImportEntityTypeMappingConditionIsNull("RTProperty1", false),
                        new FunctionImportEntityTypeMappingConditionValue("RTProperty2", 4),
                        new FunctionImportEntityTypeMappingConditionValue("FakeCondition", true)
                    }
                ));

            var mappingItemCollection = 
                new StorageMappingItemCollection(
                    new EdmItemCollection(EdmModel.CreateConceptualModel()), 
                    new StoreItemCollection(
                        EdmModel.CreateStoreModel(ProviderRegistry.Sql2008_ProviderInfo, ProviderRegistry.Sql2008_ProviderManifest)), 
                        new string[0]);

            var containerMapping = 
                new EntityContainerMapping(
                    new EntityContainer("C", DataSpace.CSpace), new EntityContainer("S", DataSpace.SSpace), mappingItemCollection, false);

            var functionImportMapping =
                new FunctionImportMappingNonComposable(
                   functionImport,
                   storeFunction,
                   new []
                   {
                       functionImportResultMapping
                   },
                   containerMapping);

            containerMapping.AddFunctionImportMapping(functionImportMapping);

            var fixture = new Fixture();
            fixture.Writer.WriteFunctionImportMappingElement(functionImportMapping);
            Assert.Equal(
                @"<FunctionImportMapping FunctionName=""Ns.Store.f_s"" FunctionImportName=""f_c"">
  <ResultMapping>
    <EntityTypeMapping TypeName=""Ns.ET"">
      <ScalarProperty Name=""ETProperty1"" ColumnName=""RTProperty1"" />
      <ScalarProperty Name=""ETProperty2"" ColumnName=""RTProperty2"" />
      <Condition ColumnName=""RTProperty1"" IsNull=""false"" />
      <Condition ColumnName=""RTProperty2"" Value=""4"" />
      <Condition ColumnName=""FakeCondition"" Value=""1"" />
    </EntityTypeMapping>
  </ResultMapping>
</FunctionImportMapping>",
                fixture.ToString());
        }
        public void WriteFunctionImportMappingElement_does_not_write_result_mapping_for_non_composable_functions_mapped_implicitly()
        {
            var typeUsage =
                TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32));

            var complexTypeProperty1 = new EdmProperty("CTProperty1", typeUsage);
            var complexTypeProperty2 = new EdmProperty("CTProperty2", typeUsage);

            var complexType = new ComplexType("CT", "Ns", DataSpace.CSpace);
            complexType.AddMember(complexTypeProperty1);
            complexType.AddMember(complexTypeProperty2);

            var functionImport =
                new EdmFunction(
                    "f_c", "Ns", DataSpace.CSpace,
                    new EdmFunctionPayload
                    {
                        IsComposable = false,
                        IsFunctionImport = true,
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "ReturnValue",
                                            TypeUsage.CreateDefaultTypeUsage(complexType.GetCollectionType()),
                                            ParameterMode.ReturnValue)
                                    },
                    });

            typeUsage = ProviderRegistry.Sql2008_ProviderManifest.GetStoreType(typeUsage);
            var rowTypeProperty1 = new EdmProperty("RTProperty1", typeUsage);
            var rowTypeProperty2 = new EdmProperty("RTProperty2", typeUsage);
            var rowType = new RowType(new[] { rowTypeProperty1, rowTypeProperty2 });

            var storeFunction =
                new EdmFunction(
                    "f_s", "Ns.Store", DataSpace.SSpace,
                    new EdmFunctionPayload
                    {
                        IsComposable = false,
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "Return",
                                            TypeUsage.CreateDefaultTypeUsage(rowType),
                                            ParameterMode.ReturnValue)
                                    },
                    });

            var functionImportMapping = 
                new FunctionImportMappingNonComposable(
                   functionImport,
                   storeFunction,
                   new FunctionImportResultMapping[0],
                   new EntityContainerMapping(new EntityContainer("C", DataSpace.SSpace)));

            var fixture = new Fixture();
            fixture.Writer.WriteFunctionImportMappingElement(functionImportMapping);
            Assert.Equal(
                @"<FunctionImportMapping FunctionName=""Ns.Store.f_s"" FunctionImportName=""f_c"" />",
                fixture.ToString());
        }
 internal FunctionColumnMapGenerator(
     FunctionImportMappingNonComposable mapping,
     int resultSetIndex,
     EntitySet entitySet,
     StructuralType baseStructuralType,
     ColumnMapFactory columnMapFactory)
 {
     _mapping = mapping;
     _entitySet = entitySet;
     _baseStructuralType = baseStructuralType;
     _resultSetIndex = resultSetIndex;
     _columnMapFactory = columnMapFactory;
 }
        /// <summary>
        ///     Determines the store type for a function import.
        /// </summary>
        private TypeUsage DetermineStoreResultType(
            FunctionImportMappingNonComposable mapping, int resultSetIndex, out IColumnMapGenerator columnMapGenerator)
        {
            // Determine column maps and infer result types for the mapped function. There are four varieties:
            // Collection(Entity)
            // Collection(PrimitiveType)
            // Collection(ComplexType)
            // No result type
            TypeUsage storeResultType;
            {
                StructuralType baseStructuralType;
                var functionImport = mapping.FunctionImport;

                // Collection(Entity) or Collection(ComplexType)
                if (MetadataHelper.TryGetFunctionImportReturnType(functionImport, resultSetIndex, out baseStructuralType))
                {
                    ValidateEdmResultType(baseStructuralType, functionImport);

                    //Note: Defensive check for historic reasons, we expect functionImport.EntitySets.Count > resultSetIndex 
                    var entitySet = functionImport.EntitySets.Count > resultSetIndex ? functionImport.EntitySets[resultSetIndex] : null;

                    columnMapGenerator = new FunctionColumnMapGenerator(
                        mapping, resultSetIndex, entitySet, baseStructuralType, _columnMapFactory);

                    // We don't actually know the return type for the stored procedure, but we can infer
                    // one based on the mapping (i.e.: a column for every property of the mapped types
                    // and for all discriminator columns)
                    storeResultType = mapping.GetExpectedTargetResultType(resultSetIndex);
                }

                    // Collection(PrimitiveType)
                else
                {
                    var returnParameter = MetadataHelper.GetReturnParameter(functionImport, resultSetIndex);
                    if (returnParameter != null
                        && returnParameter.TypeUsage != null)
                    {
                        // Get metadata description of the return type 
                        storeResultType = returnParameter.TypeUsage;
                        Debug.Assert(
                            storeResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType,
                            "FunctionImport currently supports only collection result type");
                        var elementType = ((CollectionType)storeResultType.EdmType).TypeUsage;
                        Debug.Assert(
                            Helper.IsScalarType(elementType.EdmType),
                            "FunctionImport supports only Collection(Entity), Collection(Enum) and Collection(Primitive)");

                        // Build collection column map where the first column of the store result is assumed
                        // to contain the primitive type values.
                        var scalarColumnMap = new ScalarColumnMap(elementType, string.Empty, 0, 0);
                        var collectionColumnMap = new SimpleCollectionColumnMap(
                            storeResultType,
                            string.Empty, scalarColumnMap, null, null);
                        columnMapGenerator = new ConstantColumnMapGenerator(collectionColumnMap, 1);
                    }

                        // No result type
                    else
                    {
                        storeResultType = null;
                        columnMapGenerator = new ConstantColumnMapGenerator(null, 0);
                    }
                }
            }
            return storeResultType;
        }
        private static ScalarColumnMap[] CreateDiscriminatorColumnMaps(
            DbDataReader storeDataReader, FunctionImportMappingNonComposable mapping, int resultIndex)
        {
            // choose an arbitrary type for discriminator columns -- the type is not
            // actually statically known
            EdmType discriminatorType =
                MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String);
            var discriminatorTypeUsage =
                TypeUsage.Create(discriminatorType);

            var discriminatorColumnNames = mapping.GetDiscriminatorColumns(resultIndex);
            var discriminatorColumns = new ScalarColumnMap[discriminatorColumnNames.Count];
            for (var i = 0; i < discriminatorColumns.Length; i++)
            {
                var columnName = discriminatorColumnNames[i];
                var columnMap = new ScalarColumnMap(
                    discriminatorTypeUsage, columnName, 0,
                    GetDiscriminatorOrdinalFromReader(storeDataReader, columnName, mapping.FunctionImport));
                discriminatorColumns[i] = columnMap;
            }
            return discriminatorColumns;
        }
        public void WriteFunctionImportMappingElement(FunctionImportMappingNonComposable functionImportMapping)
        {
            DebugCheck.NotNull(functionImportMapping);

            WriteFunctionImportMappingStartElement(functionImportMapping);

            foreach (var resultMapping in functionImportMapping.ResultMappings)
            {
                WriteFunctionImportResultMappingElement(resultMapping);
            }

            WriteFunctionImportEndElement();
        }
        public void Can_create_non_composable_function_with_multiple_results()
        {
            DbProviderManifest providerManifest;
            var containerMapping = GetContainerMapping(out providerManifest);

            var cTypeUsageInt = TypeUsage.Create(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32),
                new[]
                {
                    Facet.Create(MetadataItem.NullableFacetDescription, false) 
                });
            var sTypeUsageInt = TypeUsage.Create(
                providerManifest.GetStoreType(cTypeUsageInt).EdmType,
                new[]
                {
                    Facet.Create(MetadataItem.NullableFacetDescription, false) 
                });
            var cTypeUsageString = TypeUsage.CreateDefaultTypeUsage(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String));
            var sTypeUsageString = providerManifest.GetStoreType(cTypeUsageString);

            var complexType = ComplexType.Create(
                "RT1", "N", DataSpace.CSpace,
                new[]
                {
                    EdmProperty.Create("P1", cTypeUsageInt),
                    EdmProperty.Create("P2", cTypeUsageString)
                },
                null);

            var entityType = EntityType.Create(
                "RT2", "N", DataSpace.CSpace,
                new[] { "P3" },
                new[]
                {
                    EdmProperty.Create("P3", cTypeUsageInt),
                    EdmProperty.Create("P4", cTypeUsageString),
                },
                null);

            var rowType1 = RowType.Create(
                new[]
                {
                    EdmProperty.Create("C1", sTypeUsageInt),
                    EdmProperty.Create("C2", sTypeUsageString)
                },
                null);

            var rowType2 = RowType.Create(
                new[]
                {
                    EdmProperty.Create("C3", sTypeUsageInt),
                    EdmProperty.Create("C4", sTypeUsageString)
                },
                null);

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
                {
                    IsComposable = false,
                    ReturnParameters = new[]
                    {
                        FunctionParameter.Create("R1", complexType.GetCollectionType(), ParameterMode.ReturnValue),
                        FunctionParameter.Create("R2", entityType.GetCollectionType(), ParameterMode.ReturnValue) 
                    },
                    EntitySets = new[]
                    {
                        new EntitySet(),
                        new EntitySet() 
                    }
                },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
                {
                    IsComposable = false,
                    ReturnParameters = new[]
                    { 
                        FunctionParameter.Create("R1", rowType1.GetCollectionType(), ParameterMode.ReturnValue),
                        FunctionParameter.Create("R2", rowType2.GetCollectionType(), ParameterMode.ReturnValue)
                    },
                    EntitySets = new []
                    {
                        new EntitySet(),
                        new EntitySet() 
                    }
                },
                null);

            var resultMappings
                = new List<FunctionImportResultMapping>
                  {
                      new FunctionImportResultMapping(),
                      new FunctionImportResultMapping()
                  };

            resultMappings[0].AddTypeMapping(new FunctionImportComplexTypeMapping(
                complexType,
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("P1", "C1"),
                    new FunctionImportReturnTypeScalarPropertyMapping("P2", "C2"),
                }));

            resultMappings[1].AddTypeMapping(new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new [] { entityType },
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("P3", "C3"),
                    new FunctionImportReturnTypeScalarPropertyMapping("P4", "C4")
                },
                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>()));

            var functionImportMapping = new FunctionImportMappingNonComposable(
                functionImport,
                targetFunction,
                resultMappings,
                containerMapping);

            Assert.Equal(resultMappings.Count, functionImportMapping.ResultMappings.Count);

            functionImportMapping.ResultMappings.Each(m => Assert.False(m.IsReadOnly));
            functionImportMapping.SetReadOnly();
            functionImportMapping.ResultMappings.Each(m => Assert.True(m.IsReadOnly));
        }
Exemple #11
0
        public void Can_create_non_composable_function_with_multiple_results()
        {
            DbProviderManifest providerManifest;
            var containerMapping = GetContainerMapping(out providerManifest);

            var cTypeUsageInt = TypeUsage.Create(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32),
                new[]
            {
                Facet.Create(MetadataItem.NullableFacetDescription, false)
            });
            var sTypeUsageInt = TypeUsage.Create(
                providerManifest.GetStoreType(cTypeUsageInt).EdmType,
                new[]
            {
                Facet.Create(MetadataItem.NullableFacetDescription, false)
            });
            var cTypeUsageString = TypeUsage.CreateDefaultTypeUsage(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String));
            var sTypeUsageString = providerManifest.GetStoreType(cTypeUsageString);

            var complexType = ComplexType.Create(
                "RT1", "N", DataSpace.CSpace,
                new[]
            {
                EdmProperty.Create("P1", cTypeUsageInt),
                EdmProperty.Create("P2", cTypeUsageString)
            },
                null);

            var entityType = EntityType.Create(
                "RT2", "N", DataSpace.CSpace,
                new[] { "P3" },
                new[]
            {
                EdmProperty.Create("P3", cTypeUsageInt),
                EdmProperty.Create("P4", cTypeUsageString),
            },
                null);

            var rowType1 = RowType.Create(
                new[]
            {
                EdmProperty.Create("C1", sTypeUsageInt),
                EdmProperty.Create("C2", sTypeUsageString)
            },
                null);

            var rowType2 = RowType.Create(
                new[]
            {
                EdmProperty.Create("C3", sTypeUsageInt),
                EdmProperty.Create("C4", sTypeUsageString)
            },
                null);

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
            {
                IsComposable     = false,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R1", complexType.GetCollectionType(), ParameterMode.ReturnValue),
                    FunctionParameter.Create("R2", entityType.GetCollectionType(), ParameterMode.ReturnValue)
                },
                EntitySets = new[]
                {
                    new EntitySet(),
                    new EntitySet()
                }
            },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
            {
                IsComposable     = false,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R1", rowType1.GetCollectionType(), ParameterMode.ReturnValue),
                    FunctionParameter.Create("R2", rowType2.GetCollectionType(), ParameterMode.ReturnValue)
                },
                EntitySets = new []
                {
                    new EntitySet(),
                    new EntitySet()
                }
            },
                null);

            var resultMappings
                = new List <FunctionImportResultMapping>
                {
                new FunctionImportResultMapping(),
                new FunctionImportResultMapping()
                };

            resultMappings[0].AddTypeMapping(new FunctionImportComplexTypeMapping(
                                                 complexType,
                                                 new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("P1", "C1"),
                new FunctionImportReturnTypeScalarPropertyMapping("P2", "C2"),
            }));

            resultMappings[1].AddTypeMapping(new FunctionImportEntityTypeMapping(
                                                 Enumerable.Empty <EntityType>(),
                                                 new [] { entityType },
                                                 new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("P3", "C3"),
                new FunctionImportReturnTypeScalarPropertyMapping("P4", "C4")
            },
                                                 Enumerable.Empty <FunctionImportEntityTypeMappingCondition>()));

            var functionImportMapping = new FunctionImportMappingNonComposable(
                functionImport,
                targetFunction,
                resultMappings,
                containerMapping);

            Assert.Equal(resultMappings.Count, functionImportMapping.ResultMappings.Count);

            functionImportMapping.ResultMappings.Each(m => Assert.False(m.IsReadOnly));
            functionImportMapping.SetReadOnly();
            functionImportMapping.ResultMappings.Each(m => Assert.True(m.IsReadOnly));
        }