示例#1
0
        /// <summary>
        /// Initializes a new FunctionImportMappingComposable instance.
        /// </summary>
        /// <param name="functionImport">The model function import.</param>
        /// <param name="targetFunction">The store composable function.</param>
        /// <param name="resultMapping">The result mapping for the function import.</param>
        /// <param name="containerMapping">The parent container mapping.</param>
        public FunctionImportMappingComposable(
            EdmFunction functionImport,
            EdmFunction targetFunction,
            FunctionImportResultMapping resultMapping,
            EntityContainerMapping containerMapping)
            : base(Check.NotNull <EdmFunction>(functionImport, nameof(functionImport)), Check.NotNull <EdmFunction>(targetFunction, nameof(targetFunction)))
        {
            Check.NotNull <FunctionImportResultMapping>(resultMapping, nameof(resultMapping));
            Check.NotNull <EntityContainerMapping>(containerMapping, nameof(containerMapping));
            if (!functionImport.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable((object)nameof(functionImport)));
            }
            if (!targetFunction.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable((object)nameof(targetFunction)));
            }
            EdmType returnType;

            if (!MetadataHelper.TryGetFunctionImportReturnType <EdmType>(functionImport, 0, out returnType))
            {
                throw new ArgumentException(Strings.InvalidReturnTypeForComposableFunction);
            }
            EdmFunction edmFunction = containerMapping.StorageMappingItemCollection != null?containerMapping.StorageMappingItemCollection.StoreItemCollection.ConvertToCTypeFunction(targetFunction) : StoreItemCollection.ConvertFunctionSignatureToCType(targetFunction);

            RowType tvfReturnType1 = TypeHelpers.GetTvfReturnType(edmFunction);
            RowType tvfReturnType2 = TypeHelpers.GetTvfReturnType(targetFunction);

            if (tvfReturnType1 == null)
            {
                throw new ArgumentException(Strings.Mapping_FunctionImport_ResultMapping_InvalidSType((object)functionImport.Identity), nameof(functionImport));
            }
            List <EdmSchemaError> parsingErrors = new List <EdmSchemaError>();
            FunctionImportMappingComposableHelper composableHelper = new FunctionImportMappingComposableHelper(containerMapping, string.Empty, parsingErrors);
            FunctionImportMappingComposable       mapping;

            if (Helper.IsStructuralType(returnType))
            {
                composableHelper.TryCreateFunctionImportMappingComposableWithStructuralResult(functionImport, edmFunction, resultMapping.SourceList, tvfReturnType1, tvfReturnType2, (IXmlLineInfo)LineInfo.Empty, out mapping);
            }
            else
            {
                composableHelper.TryCreateFunctionImportMappingComposableWithScalarResult(functionImport, edmFunction, targetFunction, returnType, tvfReturnType1, (IXmlLineInfo)LineInfo.Empty, out mapping);
            }
            if (mapping == null)
            {
                throw new InvalidOperationException(parsingErrors.Count > 0 ? parsingErrors[0].Message : string.Empty);
            }
            this._containerMapping        = mapping._containerMapping;
            this.m_commandParameters      = mapping.m_commandParameters;
            this.m_structuralTypeMappings = mapping.m_structuralTypeMappings;
            this.m_targetFunctionKeys     = mapping.m_targetFunctionKeys;
            this._resultMapping           = resultMapping;
        }
        public void Can_create_composable_function_import_with_scalar_collection_result()
        {
            DbProviderManifest providerManifest;
            var containerMapping = GetContainerMapping(out providerManifest);

            var cTypeUsageString = TypeUsage.CreateDefaultTypeUsage(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String));
            var sTypeUsageString = providerManifest.GetStoreType(cTypeUsageString);

            var rowType = RowType.Create(
                new[]
            {
                EdmProperty.Create("C", sTypeUsageString),
            },
                null);

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", cTypeUsageString.EdmType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var resultMapping = new FunctionImportResultMapping();

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Null(functionImportMapping.StructuralTypeMappings);
            Assert.Null(functionImportMapping.TvfKeys);
        }
        public void SetReadOnly_is_called_on_child_mapping_items()
        {
            var resultMapping = new FunctionImportResultMapping();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType },
                new Collection<FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>());

            resultMapping.AddTypeMapping(typeMapping);

            Assert.False(typeMapping.IsReadOnly);
            resultMapping.SetReadOnly();
            Assert.True(typeMapping.IsReadOnly);
        }
        public void SetReadOnly_is_called_on_child_mapping_items()
        {
            var resultMapping = new FunctionImportResultMapping();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType },
                new Collection <FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty <FunctionImportEntityTypeMappingCondition>());

            resultMapping.AddTypeMapping(typeMapping);

            Assert.False(typeMapping.IsReadOnly);
            resultMapping.SetReadOnly();
            Assert.True(typeMapping.IsReadOnly);
        }
        public void Cannot_add_type_mapping_if_read_only()
        {
            var resultMapping = new FunctionImportResultMapping();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType },
                new Collection<FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>());

            resultMapping.SetReadOnly();

            Assert.Equal(
                Strings.OperationOnReadOnlyItem,
                Assert.Throws<InvalidOperationException>(
                    () => resultMapping.AddTypeMapping(typeMapping)).Message);
        }
        public void Cannot_add_type_mapping_if_read_only()
        {
            var resultMapping = new FunctionImportResultMapping();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType },
                new Collection <FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty <FunctionImportEntityTypeMappingCondition>());

            resultMapping.SetReadOnly();

            Assert.Equal(
                Strings.OperationOnReadOnlyItem,
                Assert.Throws <InvalidOperationException>(
                    () => resultMapping.AddTypeMapping(typeMapping)).Message);
        }
        public void Can_add_get_remove_type_mapping()
        {
            var resultMapping = new FunctionImportResultMapping();

            Assert.Empty(resultMapping.TypeMappings);

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType },
                new Collection <FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty <FunctionImportEntityTypeMappingCondition>());

            resultMapping.AddTypeMapping(typeMapping);

            Assert.Equal(1, resultMapping.TypeMappings.Count);
            Assert.Same(typeMapping, resultMapping.TypeMappings[0]);

            resultMapping.RemoveTypeMapping(typeMapping);

            Assert.Empty(resultMapping.TypeMappings);
        }
        public void Can_add_get_remove_type_mapping()
        {
            var resultMapping = new FunctionImportResultMapping();

            Assert.Empty(resultMapping.TypeMappings);

            var entityType = new EntityType("E", "N", DataSpace.CSpace);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType },
                new Collection<FunctionImportReturnTypePropertyMapping>(),
                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>());

            resultMapping.AddTypeMapping(typeMapping);
            
            Assert.Equal(1, resultMapping.TypeMappings.Count);
            Assert.Same(typeMapping, resultMapping.TypeMappings[0]);

            resultMapping.RemoveTypeMapping(typeMapping);

            Assert.Empty(resultMapping.TypeMappings);
        }
        public void Can_create_composable_function_import_with_entity_type_collection_result()
        {
            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 entityType = EntityType.Create(
                "RT", "N", DataSpace.CSpace,
                new[] { "PId" },
                new[]
            {
                EdmProperty.Create("PId", cTypeUsageInt),
                EdmProperty.Create("P", cTypeUsageInt),
            },
                null);


            var rowType = RowType.Create(
                new[]
            {
                EdmProperty.Create("CId", sTypeUsageInt),
                EdmProperty.Create("C", sTypeUsageInt),
            },
                null);

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", entityType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType },
                new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("PId", "CId"),
                new FunctionImportReturnTypeScalarPropertyMapping("P", "C"),
            },
                Enumerable.Empty <FunctionImportEntityTypeMappingCondition>());

            var resultMapping = new FunctionImportResultMapping();

            resultMapping.AddTypeMapping(typeMapping);

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings.Count);
            Assert.Equal(1, functionImportMapping.TvfKeys.Length);

            Assert.False(resultMapping.IsReadOnly);
            functionImportMapping.SetReadOnly();
            Assert.True(resultMapping.IsReadOnly);
        }
        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());
        }
        /// <summary>
        /// Initializes a new FunctionImportMappingComposable instance.
        /// </summary>
        /// <param name="functionImport">The model function import.</param>
        /// <param name="targetFunction">The store composable function.</param>
        /// <param name="resultMapping">The result mapping for the function import.</param>
        /// <param name="containerMapping">The parent container mapping.</param>
        public FunctionImportMappingComposable(
            EdmFunction functionImport,
            EdmFunction targetFunction,
            FunctionImportResultMapping resultMapping,
            EntityContainerMapping containerMapping)
            : base(
                Check.NotNull(functionImport, "functionImport"),
                Check.NotNull(targetFunction, "targetFunction"))
        {
            Check.NotNull(resultMapping, "resultMapping");
            Check.NotNull(containerMapping, "containerMapping");

            if (!functionImport.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("functionImport"));
            }

            if (!targetFunction.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("targetFunction"));
            }

            if (functionImport.EntitySet != null)
            {
                throw new NotSupportedException(Strings.ComposableFunctionImportsReturningEntitiesNotSupported);
            }

            EdmType resultType;

            if (!MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultType))
            {
                throw new ArgumentException(Strings.InvalidReturnTypeForComposableFunction);
            }

            // Function mapping is allowed only for TVFs on the s-space.
            var cTypeTargetFunction = containerMapping.StorageMappingItemCollection.StoreItemCollection.ConvertToCTypeFunction(targetFunction);
            var cTypeTvfElementType = TypeHelpers.GetTvfReturnType(cTypeTargetFunction);
            var sTypeTvfElementType = TypeHelpers.GetTvfReturnType(targetFunction);

            if (cTypeTvfElementType == null)
            {
                Debug.Assert(sTypeTvfElementType == null);

                throw new ArgumentException(
                          Strings.Mapping_FunctionImport_ResultMapping_InvalidSType(functionImport.Identity),
                          "functionImport");
            }

            var errors = new List <EdmSchemaError>();
            var functionImportHelper = new FunctionImportMappingComposableHelper(
                containerMapping,
                String.Empty,
                errors);

            FunctionImportMappingComposable mapping;

            if (Helper.IsStructuralType(resultType))
            {
                functionImportHelper.TryCreateFunctionImportMappingComposableWithStructuralResult(
                    functionImport,
                    cTypeTargetFunction,
                    resultMapping.SourceList,
                    cTypeTvfElementType,
                    sTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }
            else
            {
                Debug.Assert(TypeSemantics.IsScalarType(resultType));
                Debug.Assert(resultMapping.TypeMappings.Count == 0);

                functionImportHelper.TryCreateFunctionImportMappingComposableWithScalarResult(
                    functionImport,
                    cTypeTargetFunction,
                    targetFunction,
                    resultType,
                    cTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }

            if (mapping == null)
            {
                throw new InvalidOperationException(errors.Count > 0 ? errors[0].Message : String.Empty);
            }

            _containerMapping        = mapping._containerMapping;
            m_commandParameters      = mapping.m_commandParameters;
            m_structuralTypeMappings = mapping.m_structuralTypeMappings;
            m_targetFunctionKeys     = mapping.m_targetFunctionKeys;
            _resultMapping           = resultMapping;
        }
        public void Can_create_composable_function_import_with_entity_type_collection_result()
        {
            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 entityType = EntityType.Create(
                "RT", "N", DataSpace.CSpace,
                new[] { "PId" },
                new[]
                {
                    EdmProperty.Create("PId", cTypeUsageInt),
                    EdmProperty.Create("P", cTypeUsageInt),
                },
                null);


            var rowType = RowType.Create(
                new[]
                {
                    EdmProperty.Create("CId", sTypeUsageInt),
                    EdmProperty.Create("C", sTypeUsageInt),
                },
                null);

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    {
                        FunctionParameter.Create("R", entityType.GetCollectionType(), ParameterMode.ReturnValue) 
                    }
                },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    { 
                        FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                    }
                },
                null);

            var typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType },
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("PId", "CId"),
                    new FunctionImportReturnTypeScalarPropertyMapping("P", "C"),
                },
                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>());

            var resultMapping = new FunctionImportResultMapping();
            resultMapping.AddTypeMapping(typeMapping);

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings.Count);
            Assert.Equal(1, functionImportMapping.TvfKeys.Length);

            Assert.False(resultMapping.IsReadOnly);
            functionImportMapping.SetReadOnly();
            Assert.True(resultMapping.IsReadOnly);
        }
        private void WriteFunctionImportResultMappingElement(FunctionImportResultMapping resultMapping)
        {
            DebugCheck.NotNull(resultMapping);
            _xmlWriter.WriteStartElement(MslConstructs.FunctionImportMappingResultMapping);

            foreach (var typeMapping in resultMapping.TypeMappings)
            {
                var entityTypeMapping = typeMapping as FunctionImportEntityTypeMapping;
                if (entityTypeMapping != null)
                {
                    WriteFunctionImportEntityTypeMappingElement(entityTypeMapping);
                }
                else
                {
                    Debug.Assert(typeMapping is FunctionImportComplexTypeMapping, "Unexpected mapping kind.");

                    WriteFunctionImportComplexTypeMappingElement((FunctionImportComplexTypeMapping)typeMapping);
                }
            }

            _xmlWriter.WriteEndElement();
        }
        /// <summary>
        /// Initializes a new FunctionImportMappingComposable instance.
        /// </summary>
        /// <param name="functionImport">The model function import.</param>
        /// <param name="targetFunction">The store composable function.</param>
        /// <param name="resultMapping">The result mapping for the function import.</param>
        /// <param name="containerMapping">The parent container mapping.</param>
        public FunctionImportMappingComposable(
            EdmFunction functionImport,
            EdmFunction targetFunction,
            FunctionImportResultMapping resultMapping,
            EntityContainerMapping containerMapping)
            : base(
                Check.NotNull(functionImport, "functionImport"), 
                Check.NotNull(targetFunction, "targetFunction"))
        {
            Check.NotNull(resultMapping, "resultMapping");
            Check.NotNull(containerMapping, "containerMapping");

            if (!functionImport.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("functionImport"));
            }

            if (!targetFunction.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("targetFunction"));
            }

            EdmType resultType;
            if (!MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultType))
            {
                throw new ArgumentException(Strings.InvalidReturnTypeForComposableFunction);
            }

            // when this method is invoked when a CodeFirst model is being built (e.g. from a custom convention) the
            // StorageMappingItemCollection will be null. In this case we can call the converting method directly which
            // will return the correct result but the result won't be memoized. This however does not matter at this 
            // point since the model is still being constructed.
            var cTypeTargetFunction =
                containerMapping.StorageMappingItemCollection != null 
                ? containerMapping.StorageMappingItemCollection.StoreItemCollection.ConvertToCTypeFunction(targetFunction)
                : StoreItemCollection.ConvertFunctionSignatureToCType(targetFunction);
            var cTypeTvfElementType = TypeHelpers.GetTvfReturnType(cTypeTargetFunction);
            var sTypeTvfElementType = TypeHelpers.GetTvfReturnType(targetFunction);

            if (cTypeTvfElementType == null)
            {
                Debug.Assert(sTypeTvfElementType == null);

                throw new ArgumentException(
                    Strings.Mapping_FunctionImport_ResultMapping_InvalidSType(functionImport.Identity),
                    "functionImport");
            }

            var errors = new List<EdmSchemaError>();           
            var functionImportHelper = new FunctionImportMappingComposableHelper(
                containerMapping,
                String.Empty,
                errors);

            FunctionImportMappingComposable mapping;

            if (Helper.IsStructuralType(resultType))
            {
                functionImportHelper.TryCreateFunctionImportMappingComposableWithStructuralResult(
                    functionImport,
                    cTypeTargetFunction,
                    resultMapping.SourceList,
                    cTypeTvfElementType,
                    sTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }
            else
            {
                Debug.Assert(TypeSemantics.IsScalarType(resultType));
                Debug.Assert(resultMapping.TypeMappings.Count == 0);

                functionImportHelper.TryCreateFunctionImportMappingComposableWithScalarResult(
                    functionImport,
                    cTypeTargetFunction,
                    targetFunction,
                    resultType,
                    cTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }

            if (mapping == null)
            {
                throw new InvalidOperationException(errors.Count > 0 ? errors[0].Message : String.Empty);
            }

            _containerMapping = mapping._containerMapping;
            m_commandParameters = mapping.m_commandParameters;
            m_structuralTypeMappings = mapping.m_structuralTypeMappings;
            m_targetFunctionKeys = mapping.m_targetFunctionKeys;
            _resultMapping = resultMapping;
        }
        public void Can_create_composable_function_import_with_entity_type_hierarchy()
        {
            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 itemCollection = containerMapping.StorageMappingItemCollection.EdmItemCollection.GetItems<EntityType>();
            var baseEntityType = itemCollection.Single(et => et.Name == "E");
            var entityType1 = itemCollection.Single(et => et.Name == "E1");
            var entityType2 = itemCollection.Single(et => et.Name == "E2");

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

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    {
                        FunctionParameter.Create("R", baseEntityType.GetCollectionType(), ParameterMode.ReturnValue) 
                    }
                },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    { 
                        FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                    }
                },
                null);

            var resultMapping = new FunctionImportResultMapping();

            var typeMapping = new FunctionImportEntityTypeMapping(
                new[] { baseEntityType },
                Enumerable.Empty<EntityType>(),
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("Id", "CId"),
                    new FunctionImportReturnTypeScalarPropertyMapping("P", "C"),
                    new FunctionImportReturnTypeScalarPropertyMapping("Discriminator", "CD"),
                },
                Enumerable.Empty<FunctionImportEntityTypeMappingConditionValue>());
            resultMapping.AddTypeMapping(typeMapping);

            typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType1 },
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("P1", "C1"),
                },
                new  []
                {
                    new FunctionImportEntityTypeMappingConditionValue("CD", "E1")
                });
            resultMapping.AddTypeMapping(typeMapping);

            typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty<EntityType>(),
                new[] { entityType2 },
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("P2", "C2"),
                },
                new []
                {
                    new FunctionImportEntityTypeMappingConditionValue("CD", "E2")
                });
            resultMapping.AddTypeMapping(typeMapping);

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Equal(2, functionImportMapping.StructuralTypeMappings.Count);            
            Assert.Equal(1, functionImportMapping.TvfKeys.Length);

            Assert.Equal(typeof(E1).Name, functionImportMapping.StructuralTypeMappings[0].Item1.Name);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings[0].Item2.Count());
            Assert.Equal(3, functionImportMapping.StructuralTypeMappings[0].Item3.Count());

            Assert.Equal(typeof(E2).Name, functionImportMapping.StructuralTypeMappings[1].Item1.Name);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings[0].Item2.Count());
            Assert.Equal(3, functionImportMapping.StructuralTypeMappings[0].Item3.Count());
        }
        public void Can_create_composable_function_import_with_entity_type_hierarchy()
        {
            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 itemCollection = containerMapping.StorageMappingItemCollection.EdmItemCollection.GetItems <EntityType>();
            var baseEntityType = itemCollection.Single(et => et.Name == "E");
            var entityType1    = itemCollection.Single(et => et.Name == "E1");
            var entityType2    = itemCollection.Single(et => et.Name == "E2");

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

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", baseEntityType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
            {
                IsComposable     = true,
                ReturnParameters = new[]
                {
                    FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                }
            },
                null);

            var resultMapping = new FunctionImportResultMapping();

            var typeMapping = new FunctionImportEntityTypeMapping(
                new[] { baseEntityType },
                Enumerable.Empty <EntityType>(),
                new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("Id", "CId"),
                new FunctionImportReturnTypeScalarPropertyMapping("P", "C"),
                new FunctionImportReturnTypeScalarPropertyMapping("Discriminator", "CD"),
            },
                Enumerable.Empty <FunctionImportEntityTypeMappingConditionValue>());

            resultMapping.AddTypeMapping(typeMapping);

            typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType1 },
                new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("P1", "C1"),
            },
                new  []
            {
                new FunctionImportEntityTypeMappingConditionValue("CD", "E1")
            });
            resultMapping.AddTypeMapping(typeMapping);

            typeMapping = new FunctionImportEntityTypeMapping(
                Enumerable.Empty <EntityType>(),
                new[] { entityType2 },
                new Collection <FunctionImportReturnTypePropertyMapping>()
            {
                new FunctionImportReturnTypeScalarPropertyMapping("P2", "C2"),
            },
                new []
            {
                new FunctionImportEntityTypeMappingConditionValue("CD", "E2")
            });
            resultMapping.AddTypeMapping(typeMapping);

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Equal(2, functionImportMapping.StructuralTypeMappings.Count);
            Assert.Equal(1, functionImportMapping.TvfKeys.Length);

            Assert.Equal(typeof(E1).Name, functionImportMapping.StructuralTypeMappings[0].Item1.Name);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings[0].Item2.Count());
            Assert.Equal(3, functionImportMapping.StructuralTypeMappings[0].Item3.Count());

            Assert.Equal(typeof(E2).Name, functionImportMapping.StructuralTypeMappings[1].Item1.Name);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings[0].Item2.Count());
            Assert.Equal(3, functionImportMapping.StructuralTypeMappings[0].Item3.Count());
        }
        /// <summary>
        /// Initializes a new FunctionImportMappingComposable instance.
        /// </summary>
        /// <param name="functionImport">The model function import.</param>
        /// <param name="targetFunction">The store composable function.</param>
        /// <param name="resultMapping">The result mapping for the function import.</param>
        /// <param name="containerMapping">The parent container mapping.</param>
        public FunctionImportMappingComposable(
            EdmFunction functionImport,
            EdmFunction targetFunction,
            FunctionImportResultMapping resultMapping,
            EntityContainerMapping containerMapping)
            : base(
                Check.NotNull(functionImport, "functionImport"),
                Check.NotNull(targetFunction, "targetFunction"))
        {
            Check.NotNull(resultMapping, "resultMapping");
            Check.NotNull(containerMapping, "containerMapping");

            if (!functionImport.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("functionImport"));
            }

            if (!targetFunction.IsComposableAttribute)
            {
                throw new ArgumentException(Strings.NonComposableFunctionCannotBeMappedAsComposable("targetFunction"));
            }

            EdmType resultType;

            if (!MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultType))
            {
                throw new ArgumentException(Strings.InvalidReturnTypeForComposableFunction);
            }

            // when this method is invoked when a CodeFirst model is being built (e.g. from a custom convention) the
            // StorageMappingItemCollection will be null. In this case we can call the converting method directly which
            // will return the correct result but the result won't be memoized. This however does not matter at this
            // point since the model is still being constructed.
            var cTypeTargetFunction =
                containerMapping.StorageMappingItemCollection != null
                ? containerMapping.StorageMappingItemCollection.StoreItemCollection.ConvertToCTypeFunction(targetFunction)
                : StoreItemCollection.ConvertFunctionSignatureToCType(targetFunction);

            var cTypeTvfElementType = TypeHelpers.GetTvfReturnType(cTypeTargetFunction);
            var sTypeTvfElementType = TypeHelpers.GetTvfReturnType(targetFunction);

            if (cTypeTvfElementType == null)
            {
                Debug.Assert(sTypeTvfElementType == null);

                throw new ArgumentException(
                          Strings.Mapping_FunctionImport_ResultMapping_InvalidSType(functionImport.Identity),
                          "functionImport");
            }

            var errors = new List <EdmSchemaError>();
            var functionImportHelper = new FunctionImportMappingComposableHelper(
                containerMapping,
                String.Empty,
                errors);

            FunctionImportMappingComposable mapping;

            if (Helper.IsStructuralType(resultType))
            {
                functionImportHelper.TryCreateFunctionImportMappingComposableWithStructuralResult(
                    functionImport,
                    cTypeTargetFunction,
                    resultMapping.SourceList,
                    cTypeTvfElementType,
                    sTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }
            else
            {
                Debug.Assert(TypeSemantics.IsScalarType(resultType));
                Debug.Assert(resultMapping.TypeMappings.Count == 0);

                functionImportHelper.TryCreateFunctionImportMappingComposableWithScalarResult(
                    functionImport,
                    cTypeTargetFunction,
                    targetFunction,
                    resultType,
                    cTypeTvfElementType,
                    LineInfo.Empty,
                    out mapping);
            }

            if (mapping == null)
            {
                throw new InvalidOperationException(errors.Count > 0 ? errors[0].Message : String.Empty);
            }

            _containerMapping        = mapping._containerMapping;
            m_commandParameters      = mapping.m_commandParameters;
            m_structuralTypeMappings = mapping.m_structuralTypeMappings;
            m_targetFunctionKeys     = mapping.m_targetFunctionKeys;
            _resultMapping           = resultMapping;
        }
        public void Can_create_composable_function_import_with_complex_type_collection_result()
        {
            DbProviderManifest providerManifest;
            var containerMapping = GetContainerMapping(out providerManifest);

            var cTypeUsageString = TypeUsage.CreateDefaultTypeUsage(
                PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String));
            var sTypeUsageString = providerManifest.GetStoreType(cTypeUsageString);

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


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

            var functionImport = EdmFunction.Create(
                "F", "N", DataSpace.CSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    {
                        FunctionParameter.Create("R", complexType.GetCollectionType(), ParameterMode.ReturnValue) 
                    }
                },
                null);

            var targetFunction = EdmFunction.Create(
                "SF", "N", DataSpace.SSpace,
                new EdmFunctionPayload
                {
                    IsComposable = true,
                    ReturnParameters = new[]
                    { 
                        FunctionParameter.Create("R", rowType.GetCollectionType(), ParameterMode.ReturnValue)
                    }
                },
                null);

            var typeMapping = new FunctionImportComplexTypeMapping(
                complexType,
                new Collection<FunctionImportReturnTypePropertyMapping>()
                {
                    new FunctionImportReturnTypeScalarPropertyMapping("P1", "C1"),
                    new FunctionImportReturnTypeScalarPropertyMapping("P2", "C2"),
                });

            var resultMapping = new FunctionImportResultMapping();
            resultMapping.AddTypeMapping(typeMapping);

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                targetFunction,
                resultMapping,
                containerMapping);

            Assert.Same(resultMapping, functionImportMapping.ResultMapping);
            Assert.Equal(1, functionImportMapping.StructuralTypeMappings.Count);
            Assert.Null(functionImportMapping.TvfKeys);
        }