Ejemplo n.º 1
0
        private static DbExpression GeneratePropertyMappingView(
            PropertyMapping mapping,
            DbExpression row)
        {
            ScalarPropertyMapping scalarPropertyMapping = (ScalarPropertyMapping)mapping;

            return(FunctionImportMappingComposable.GenerateScalarPropertyMappingView(scalarPropertyMapping.Property, scalarPropertyMapping.Column, row));
        }
        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);
        }
Ejemplo n.º 3
0
        private static DbExpression GenerateScalarPropertyMappingView(
            EdmProperty edmProperty,
            EdmProperty columnProperty,
            DbExpression row)
        {
            DbExpression columnRef = FunctionImportMappingComposable.GenerateColumnRef(row, columnProperty);

            if (!TypeSemantics.IsEqual(columnRef.ResultType, edmProperty.TypeUsage))
            {
                columnRef = (DbExpression)columnRef.CastTo(edmProperty.TypeUsage);
            }
            return(columnRef);
        }
Ejemplo n.º 4
0
        private static DbExpression GenerateStructuralTypeMappingView(
            StructuralType structuralType,
            List <PropertyMapping> propertyMappings,
            DbExpression row)
        {
            List <DbExpression> dbExpressionList = new List <DbExpression>(TypeHelpers.GetAllStructuralMembers((EdmType)structuralType).Count);

            for (int index = 0; index < propertyMappings.Count; ++index)
            {
                PropertyMapping propertyMapping = propertyMappings[index];
                dbExpressionList.Add(FunctionImportMappingComposable.GeneratePropertyMappingView(propertyMapping, row));
            }
            return((DbExpression)TypeUsage.Create((EdmType)structuralType).New((IEnumerable <DbExpression>)dbExpressionList));
        }
Ejemplo n.º 5
0
        private static DbExpression GeneratePredicate(
            ConditionPropertyMapping condition,
            DbExpression row)
        {
            DbExpression columnRef = FunctionImportMappingComposable.GenerateColumnRef(row, condition.Column);

            if (!condition.IsNull.HasValue)
            {
                return((DbExpression)columnRef.Equal((DbExpression)columnRef.ResultType.Constant(condition.Value)));
            }
            if (!condition.IsNull.Value)
            {
                return((DbExpression)columnRef.IsNull().Not());
            }
            return((DbExpression)columnRef.IsNull());
        }
Ejemplo n.º 6
0
        public void Can_add_and_get_function_import_mapping()
        {
            var typeUsage =
                TypeUsage.CreateDefaultTypeUsage(
                    PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32).GetCollectionType());

            var entityContainerMapping = new EntityContainerMapping(new EntityContainer("C", DataSpace.CSpace));

            var composableFunctionMapping =
                new FunctionImportMappingComposable(
                    new EdmFunction(
                        "f", "model", DataSpace.CSpace,
                        new EdmFunctionPayload()
            {
                IsComposable     = true,
                ReturnParameters =
                    new[]
                {
                    new FunctionParameter(
                        "ReturnType",
                        typeUsage,
                        ParameterMode.ReturnValue),
                }
            }),
                    new EdmFunction(
                        "f", "store", DataSpace.SSpace,
                        new EdmFunctionPayload()
            {
                IsComposable     = true,
                ReturnParameters =
                    new[]
                {
                    new FunctionParameter(
                        "ReturnType",
                        typeUsage,
                        ParameterMode.ReturnValue),
                }
            }),
                    null);

            Assert.Empty(entityContainerMapping.FunctionImportMappings);
            entityContainerMapping.AddFunctionImportMapping(composableFunctionMapping);
            Assert.Same(composableFunctionMapping, entityContainerMapping.FunctionImportMappings.Single());
        }
Ejemplo n.º 7
0
        internal bool TryCreateFunctionImportMappingComposableWithScalarResult(
            EdmFunction functionImport,
            EdmFunction cTypeTargetFunction,
            EdmFunction sTypeTargetFunction,
            EdmType scalarResultType,
            RowType cTypeTvfElementType,
            IXmlLineInfo lineInfo,
            out FunctionImportMappingComposable mapping)
        {
            mapping = null;

            // Make sure that TVF returns exactly one column
            if (cTypeTvfElementType.Properties.Count > 1)
            {
                AddToSchemaErrors(
                    Strings.Mapping_FunctionImport_ScalarMappingToMulticolumnTVF(functionImport.Identity, sTypeTargetFunction.Identity),
                    MappingErrorCode.MappingFunctionImportScalarMappingToMulticolumnTVF, m_sourceLocation, lineInfo, m_parsingErrors);
                return(false);
            }

            // Make sure that scalarResultType agrees with the column type.
            if (
                !ValidateFunctionImportMappingResultTypeCompatibility(
                    TypeUsage.Create(scalarResultType), cTypeTvfElementType.Properties[0].TypeUsage))
            {
                AddToSchemaErrors(
                    Strings.Mapping_FunctionImport_ScalarMappingTypeMismatch(
                        functionImport.ReturnParameter.TypeUsage.EdmType.FullName,
                        functionImport.Identity,
                        sTypeTargetFunction.ReturnParameter.TypeUsage.EdmType.FullName,
                        sTypeTargetFunction.Identity),
                    MappingErrorCode.MappingFunctionImportScalarMappingTypeMismatch, m_sourceLocation, lineInfo, m_parsingErrors);
                return(false);
            }

            mapping = new FunctionImportMappingComposable(
                functionImport,
                cTypeTargetFunction,
                null,
                null,
                _entityContainerMapping);
            return(true);
        }
        public void Can_get_structural_type_mappings()
        {
            var complexType = new ComplexType("CT", "ns", DataSpace.CSpace);

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

            var structuralTypeMapping =
                new List <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > >
            {
                new Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >(
                    complexType, null, null)
            };

            var functionImportMapping =
                new FunctionImportMappingComposable(
                    functionImport,
                    new EdmFunction(
                        "f", "store", DataSpace.CSpace,
                        new EdmFunctionPayload
            {
                IsComposable = true
            }),
                    structuralTypeMapping);

            Assert.Equal(structuralTypeMapping, functionImportMapping.StructuralTypeMappings);
        }
Ejemplo n.º 9
0
        private DbExpression GenerateStructuralTypeResultMappingView(
            DbExpression storeFunctionInvoke,
            out DiscriminatorMap discriminatorMap)
        {
            discriminatorMap = (DiscriminatorMap)null;
            DbExpression dbExpression = storeFunctionInvoke;
            DbExpression queryView;

            if (this.m_structuralTypeMappings.Count == 1)
            {
                Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > structuralTypeMapping = this.m_structuralTypeMappings[0];
                StructuralType structuralType = structuralTypeMapping.Item1;
                List <ConditionPropertyMapping> conditions       = structuralTypeMapping.Item2;
                List <PropertyMapping>          propertyMappings = structuralTypeMapping.Item3;
                if (conditions.Count > 0)
                {
                    dbExpression = (DbExpression)dbExpression.Where((Func <DbExpression, DbExpression>)(row => FunctionImportMappingComposable.GenerateStructuralTypeConditionsPredicate(conditions, row)));
                }
                DbExpressionBinding input = dbExpression.BindAs("row");
                DbExpression        structuralTypeMappingView = FunctionImportMappingComposable.GenerateStructuralTypeMappingView(structuralType, propertyMappings, (DbExpression)input.Variable);
                queryView = (DbExpression)input.Project(structuralTypeMappingView);
            }
            else
            {
                DbExpressionBinding binding = dbExpression.BindAs("row");
                List <DbExpression> list    = this.m_structuralTypeMappings.Select <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >, DbExpression>((Func <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >, DbExpression>)(m => FunctionImportMappingComposable.GenerateStructuralTypeConditionsPredicate(m.Item2, (DbExpression)binding.Variable))).ToList <DbExpression>();
                binding = binding.Filter(Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>)list.ToArray(), (Func <DbExpression, DbExpression, DbExpression>)((prev, next) => (DbExpression)prev.Or(next)))).BindAs("row");
                List <DbExpression> source = new List <DbExpression>(this.m_structuralTypeMappings.Count);
                foreach (Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > structuralTypeMapping in this.m_structuralTypeMappings)
                {
                    StructuralType         structuralType   = structuralTypeMapping.Item1;
                    List <PropertyMapping> propertyMappings = structuralTypeMapping.Item3;
                    source.Add(FunctionImportMappingComposable.GenerateStructuralTypeMappingView(structuralType, propertyMappings, (DbExpression)binding.Variable));
                }
                DbExpression projection = (DbExpression)DbExpressionBuilder.Case(list.Take <DbExpression>(this.m_structuralTypeMappings.Count - 1), source.Take <DbExpression>(this.m_structuralTypeMappings.Count - 1), source[this.m_structuralTypeMappings.Count - 1]);
                queryView = (DbExpression)binding.Project(projection);
                DiscriminatorMap.TryCreateDiscriminatorMap(this.FunctionImport.EntitySet, queryView, out discriminatorMap);
            }
            return(queryView);
        }
Ejemplo n.º 10
0
 internal bool TryCreateFunctionImportMappingComposableWithScalarResult(
     EdmFunction functionImport,
     EdmFunction cTypeTargetFunction,
     EdmFunction sTypeTargetFunction,
     EdmType scalarResultType,
     RowType cTypeTvfElementType,
     IXmlLineInfo lineInfo,
     out FunctionImportMappingComposable mapping)
 {
     mapping = (FunctionImportMappingComposable)null;
     if (cTypeTvfElementType.Properties.Count > 1)
     {
         FunctionImportMappingComposableHelper.AddToSchemaErrors(Strings.Mapping_FunctionImport_ScalarMappingToMulticolumnTVF((object)functionImport.Identity, (object)sTypeTargetFunction.Identity), MappingErrorCode.MappingFunctionImportScalarMappingToMulticolumnTVF, this.m_sourceLocation, lineInfo, (IList <EdmSchemaError>) this.m_parsingErrors);
         return(false);
     }
     if (!FunctionImportMappingComposableHelper.ValidateFunctionImportMappingResultTypeCompatibility(TypeUsage.Create(scalarResultType), cTypeTvfElementType.Properties[0].TypeUsage))
     {
         FunctionImportMappingComposableHelper.AddToSchemaErrors(Strings.Mapping_FunctionImport_ScalarMappingTypeMismatch((object)functionImport.ReturnParameter.TypeUsage.EdmType.FullName, (object)functionImport.Identity, (object)sTypeTargetFunction.ReturnParameter.TypeUsage.EdmType.FullName, (object)sTypeTargetFunction.Identity), MappingErrorCode.MappingFunctionImportScalarMappingTypeMismatch, this.m_sourceLocation, lineInfo, (IList <EdmSchemaError>) this.m_parsingErrors);
         return(false);
     }
     mapping = new FunctionImportMappingComposable(functionImport, cTypeTargetFunction, (List <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > >)null, (EdmProperty[])null, this._entityContainerMapping);
     return(true);
 }
Ejemplo n.º 11
0
        public void WriteEntityContainerMappingElement_should_write_function_import_elements_mapped_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 = true,
                        IsFunctionImport = true,
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "ReturnValue",
                                            TypeUsage.CreateDefaultTypeUsage(entityType.GetCollectionType()),
                                            ParameterMode.ReturnValue)
                                    },
                        Parameters =
                            new[]
                                    {
                                        new FunctionParameter("param", typeUsage, ParameterMode.Out)
                                    }
                    });

            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
                    {
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "Return",
                                            TypeUsage.CreateDefaultTypeUsage(rowType),
                                            ParameterMode.ReturnValue)
                                    },
                        Parameters =
                            new[]
                                    {
                                        new FunctionParameter("param", typeUsage, ParameterMode.Out)
                                    }
                    });

            var structuralTypeMapping =
                new Tuple<StructuralType, List<ConditionPropertyMapping>, List<PropertyMapping>>(
                    entityType, new List<ConditionPropertyMapping>(), new List<PropertyMapping>());
            structuralTypeMapping.Item2.Add(new ConditionPropertyMapping(rowTypeProperty1, null, false));

            structuralTypeMapping.Item3.Add(new ScalarPropertyMapping(entityTypeProperty1, rowTypeProperty1));
            structuralTypeMapping.Item3.Add(new ScalarPropertyMapping(entityTypeProperty2, rowTypeProperty2));

            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                storeFunction,
                new List<Tuple<StructuralType, List<ConditionPropertyMapping>, List<PropertyMapping>>>
                    {
                        structuralTypeMapping
                    });

            var containerMapping = new EntityContainerMapping(new EntityContainer("C", DataSpace.SSpace));
            containerMapping.AddFunctionImportMapping(functionImportMapping);

            var fixture = new Fixture();
            fixture.Writer.WriteEntityContainerMappingElement(containerMapping);

            Assert.Equal(
                @"<EntityContainerMapping StorageEntityContainer="""" CdmEntityContainer=""C"">
  <FunctionImportMapping FunctionName=""Ns.Store.f_s"" FunctionImportName=""f_c"">
    <ResultMapping>
      <EntityTypeMapping TypeName=""Ns.ET"">
        <Condition IsNull=""false"" ColumnName=""RTProperty1"" />
        <ScalarProperty Name=""ETProperty1"" ColumnName=""RTProperty1"" />
        <ScalarProperty Name=""ETProperty2"" ColumnName=""RTProperty2"" />
      </EntityTypeMapping>
    </ResultMapping>
  </FunctionImportMapping>
</EntityContainerMapping>",
                fixture.ToString());
        }
Ejemplo n.º 12
0
        internal bool TryCreateFunctionImportMappingComposableWithStructuralResult(
            EdmFunction functionImport,
            EdmFunction cTypeTargetFunction,
            List <FunctionImportStructuralTypeMapping> typeMappings,
            RowType cTypeTvfElementType,
            RowType sTypeTvfElementType,
            IXmlLineInfo lineInfo,
            out FunctionImportMappingComposable mapping)
        {
            mapping = null;

            // If it is an implicit structural type mapping, add a type mapping fragment for the return type of the function import,
            // unless it is an abstract type.
            if (typeMappings.Count == 0)
            {
                StructuralType resultType;
                if (MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultType))
                {
                    if (resultType.Abstract)
                    {
                        AddToSchemaErrorWithMemberAndStructure(
                            Strings.Mapping_FunctionImport_ImplicitMappingForAbstractReturnType,
                            resultType.FullName, functionImport.Identity,
                            MappingErrorCode.MappingOfAbstractType, m_sourceLocation, lineInfo, m_parsingErrors);
                        return(false);
                    }
                    if (resultType.BuiltInTypeKind
                        == BuiltInTypeKind.EntityType)
                    {
                        typeMappings.Add(
                            new FunctionImportEntityTypeMapping(
                                Enumerable.Empty <EntityType>(),
                                new[] { (EntityType)resultType },
                                Enumerable.Empty <FunctionImportEntityTypeMappingCondition>(),
                                new Collection <FunctionImportReturnTypePropertyMapping>(),
                                new LineInfo(lineInfo)));
                    }
                    else
                    {
                        Debug.Assert(
                            resultType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                            "resultType.BuiltInTypeKind == BuiltInTypeKind.ComplexType");
                        typeMappings.Add(
                            new FunctionImportComplexTypeMapping(
                                (ComplexType)resultType,
                                new Collection <FunctionImportReturnTypePropertyMapping>(),
                                new LineInfo(lineInfo)));
                    }
                }
            }


            // 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 provide an empty EdmItemCollection which
            // will allow inferring implicit result mapping
            var edmItemCollection =
                _entityContainerMapping.StorageMappingItemCollection != null
                    ? _entityContainerMapping.StorageMappingItemCollection.EdmItemCollection
                    : new EdmItemCollection(new EdmModel(DataSpace.CSpace));

            // Validate and convert FunctionImportEntityTypeMapping elements into structure suitable for composable function import mapping.
            var functionImportKB = new FunctionImportStructuralTypeMappingKB(typeMappings, edmItemCollection);

            var structuralTypeMappings =
                new List <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > >();

            EdmProperty[] targetFunctionKeys = null;
            if (functionImportKB.MappedEntityTypes.Count > 0)
            {
                // Validate TPH ambiguity.
                if (!functionImportKB.ValidateTypeConditions(/*validateAmbiguity: */ true, m_parsingErrors, m_sourceLocation))
                {
                    return(false);
                }

                // For each mapped entity type, prepare list of conditions and list of property mappings.
                for (var i = 0; i < functionImportKB.MappedEntityTypes.Count; ++i)
                {
                    List <ConditionPropertyMapping> typeConditions;
                    List <PropertyMapping>          propertyMappings;
                    if (TryConvertToEntityTypeConditionsAndPropertyMappings(
                            functionImport,
                            functionImportKB,
                            i,
                            cTypeTvfElementType,
                            sTypeTvfElementType,
                            lineInfo, out typeConditions, out propertyMappings))
                    {
                        structuralTypeMappings.Add(
                            Tuple.Create((StructuralType)functionImportKB.MappedEntityTypes[i], typeConditions, propertyMappings));
                    }
                }
                if (structuralTypeMappings.Count
                    < functionImportKB.MappedEntityTypes.Count)
                {
                    // Some of the entity types produced errors during conversion, exit.
                    return(false);
                }

                // Infer target function keys based on the c-space entity types.
                if (!TryInferTVFKeys(structuralTypeMappings, out targetFunctionKeys))
                {
                    AddToSchemaErrorsWithMemberInfo(
                        Strings.Mapping_FunctionImport_CannotInferTargetFunctionKeys, functionImport.Identity,
                        MappingErrorCode.MappingFunctionImportCannotInferTargetFunctionKeys, m_sourceLocation, lineInfo,
                        m_parsingErrors);
                    return(false);
                }
            }
            else
            {
                ComplexType resultComplexType;
                if (MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultComplexType))
                {
                    // Gather and validate complex type property mappings.
                    List <PropertyMapping> propertyMappings;
                    if (
                        !TryConvertToPropertyMappings(
                            resultComplexType, cTypeTvfElementType, sTypeTvfElementType, functionImport, functionImportKB, lineInfo,
                            out propertyMappings))
                    {
                        return(false);
                    }
                    structuralTypeMappings.Add(
                        Tuple.Create((StructuralType)resultComplexType, new List <ConditionPropertyMapping>(), propertyMappings));
                }
                else
                {
                    Debug.Fail("Function import return type is expected to be a collection of complex type.");
                }
            }

            mapping = new FunctionImportMappingComposable(
                functionImport,
                cTypeTargetFunction,
                structuralTypeMappings,
                targetFunctionKeys,
                _entityContainerMapping);
            return(true);
        }
Ejemplo n.º 13
0
        public void WriteFunctionImportMappingElement(FunctionImportMappingComposable functionImportMapping)
        {
            DebugCheck.NotNull(functionImportMapping);

            _xmlWriter.WriteStartElement(StorageMslConstructs.FunctionImportMappingElement);
            _xmlWriter.WriteAttributeString(
                StorageMslConstructs.FunctionImportMappingFunctionNameAttribute,
                functionImportMapping.TargetFunction.FullName);
            _xmlWriter.WriteAttributeString(
                StorageMslConstructs.FunctionImportMappingFunctionImportNameAttribute,
                functionImportMapping.FunctionImport.Name);
            _xmlWriter.WriteStartElement(StorageMslConstructs.FunctionImportMappingResultMapping);

            Debug.Assert(
                functionImportMapping.StructuralTypeMappings.Count == 1,
                "multiple result sets not supported.");
            Debug.Assert(
                functionImportMapping.StructuralTypeMappings.First().Item1.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                "mapping to entity sets not supported.");

            var structuralMapping = functionImportMapping.StructuralTypeMappings.Single();
            _xmlWriter.WriteStartElement(StorageMslConstructs.ComplexTypeMappingElement);
            _xmlWriter.WriteAttributeString(StorageMslConstructs.ComplexTypeMappingTypeNameAttribute, structuralMapping.Item1.FullName);
            foreach (StorageScalarPropertyMapping propertyMapping in structuralMapping.Item3)
            {
                WritePropertyMapping(propertyMapping);
            }

            _xmlWriter.WriteEndElement();
            _xmlWriter.WriteEndElement();
            _xmlWriter.WriteEndElement();
        }
Ejemplo n.º 14
0
        public void WriteFunctionImportMappingElement(FunctionImportMappingComposable functionImportMapping)
        {
            DebugCheck.NotNull(functionImportMapping);

            WriteFunctionImportMappingStartElement(functionImportMapping);

            // no mapping written when mapping to a scalar
            if (functionImportMapping.StructuralTypeMappings != null)
            {
                _xmlWriter.WriteStartElement(MslConstructs.FunctionImportMappingResultMapping);

                Debug.Assert(
                    functionImportMapping.StructuralTypeMappings.Count == 1,
                    "multiple result sets not supported.");

                var structuralMapping = functionImportMapping.StructuralTypeMappings.Single();

                if (structuralMapping.Item1.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                {
                    _xmlWriter.WriteStartElement(MslConstructs.ComplexTypeMappingElement);
                    _xmlWriter.WriteAttributeString(MslConstructs.ComplexTypeMappingTypeNameAttribute, structuralMapping.Item1.FullName);
                }
                else
                {
                    Debug.Assert(structuralMapping.Item1.BuiltInTypeKind == BuiltInTypeKind.EntityType, "Unexpected return type");

                    _xmlWriter.WriteStartElement(MslConstructs.EntityTypeMappingElement);
                    _xmlWriter.WriteAttributeString(MslConstructs.EntityTypeMappingTypeNameAttribute, structuralMapping.Item1.FullName);

                    foreach (var conditionMapping in structuralMapping.Item2)
                    {
                        WriteConditionElement(conditionMapping);
                    }
                }

                foreach (var propertyMapping in structuralMapping.Item3)
                {
                    WritePropertyMapping(propertyMapping);
                }

                _xmlWriter.WriteEndElement();
                _xmlWriter.WriteEndElement();
            }

            WriteFunctionImportEndElement();
        }
        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 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 Can_get_structural_type_mappings()
        {
            var complexType = new ComplexType("CT", "ns", DataSpace.CSpace);

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

            var structuralTypeMapping =
                new List<Tuple<StructuralType, List<StorageConditionPropertyMapping>, List<StoragePropertyMapping>>>
                    {
                        new Tuple<StructuralType, List<StorageConditionPropertyMapping>, List<StoragePropertyMapping>>(
                            complexType, null, null)
                    };

            var functionImportMapping =
                new FunctionImportMappingComposable(
                    functionImport,
                    new EdmFunction(
                        "f", "store", DataSpace.CSpace,
                        new EdmFunctionPayload
                            {
                                IsComposable = true
                            }),
                    structuralTypeMapping);

            Assert.Equal(structuralTypeMapping, functionImportMapping.StructuralTypeMappings);
        }
Ejemplo n.º 18
0
        internal bool TryCreateFunctionImportMappingComposableWithStructuralResult(
            EdmFunction functionImport,
            EdmFunction cTypeTargetFunction,
            List <FunctionImportStructuralTypeMapping> typeMappings,
            RowType cTypeTvfElementType,
            RowType sTypeTvfElementType,
            IXmlLineInfo lineInfo,
            out FunctionImportMappingComposable mapping)
        {
            mapping = (FunctionImportMappingComposable)null;
            StructuralType returnType1;

            if (typeMappings.Count == 0 && MetadataHelper.TryGetFunctionImportReturnType <StructuralType>(functionImport, 0, out returnType1))
            {
                if (returnType1.Abstract)
                {
                    FunctionImportMappingComposableHelper.AddToSchemaErrorWithMemberAndStructure(new Func <object, object, string>(Strings.Mapping_FunctionImport_ImplicitMappingForAbstractReturnType), returnType1.FullName, functionImport.Identity, MappingErrorCode.MappingOfAbstractType, this.m_sourceLocation, lineInfo, (IList <EdmSchemaError>) this.m_parsingErrors);
                    return(false);
                }
                if (returnType1.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                {
                    typeMappings.Add((FunctionImportStructuralTypeMapping) new FunctionImportEntityTypeMapping(Enumerable.Empty <System.Data.Entity.Core.Metadata.Edm.EntityType>(), (IEnumerable <System.Data.Entity.Core.Metadata.Edm.EntityType>) new System.Data.Entity.Core.Metadata.Edm.EntityType[1]
                    {
                        (System.Data.Entity.Core.Metadata.Edm.EntityType)returnType1
                    }, Enumerable.Empty <FunctionImportEntityTypeMappingCondition>(), new Collection <FunctionImportReturnTypePropertyMapping>(), new LineInfo(lineInfo)));
                }
                else
                {
                    typeMappings.Add((FunctionImportStructuralTypeMapping) new FunctionImportComplexTypeMapping((ComplexType)returnType1, new Collection <FunctionImportReturnTypePropertyMapping>(), new LineInfo(lineInfo)));
                }
            }
            EdmItemCollection edmItemCollection = this._entityContainerMapping.StorageMappingItemCollection != null ? this._entityContainerMapping.StorageMappingItemCollection.EdmItemCollection : new EdmItemCollection(new EdmModel(DataSpace.CSpace, 3.0));
            FunctionImportStructuralTypeMappingKB functionImportKB = new FunctionImportStructuralTypeMappingKB((IEnumerable <FunctionImportStructuralTypeMapping>)typeMappings, (ItemCollection)edmItemCollection);
            List <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > > structuralTypeMappings = new List <Tuple <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> > >();

            EdmProperty[] keys = (EdmProperty[])null;
            if (functionImportKB.MappedEntityTypes.Count > 0)
            {
                if (!functionImportKB.ValidateTypeConditions(true, (IList <EdmSchemaError>) this.m_parsingErrors, this.m_sourceLocation))
                {
                    return(false);
                }
                for (int typeID = 0; typeID < functionImportKB.MappedEntityTypes.Count; ++typeID)
                {
                    List <ConditionPropertyMapping> typeConditions;
                    List <PropertyMapping>          propertyMappings;
                    if (this.TryConvertToEntityTypeConditionsAndPropertyMappings(functionImport, functionImportKB, typeID, cTypeTvfElementType, sTypeTvfElementType, lineInfo, out typeConditions, out propertyMappings))
                    {
                        structuralTypeMappings.Add(Tuple.Create <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >((StructuralType)functionImportKB.MappedEntityTypes[typeID], typeConditions, propertyMappings));
                    }
                }
                if (structuralTypeMappings.Count < functionImportKB.MappedEntityTypes.Count)
                {
                    return(false);
                }
                if (!FunctionImportMappingComposableHelper.TryInferTVFKeys(structuralTypeMappings, out keys))
                {
                    FunctionImportMappingComposableHelper.AddToSchemaErrorsWithMemberInfo(new Func <object, string>(Strings.Mapping_FunctionImport_CannotInferTargetFunctionKeys), functionImport.Identity, MappingErrorCode.MappingFunctionImportCannotInferTargetFunctionKeys, this.m_sourceLocation, lineInfo, (IList <EdmSchemaError>) this.m_parsingErrors);
                    return(false);
                }
            }
            else
            {
                ComplexType returnType2;
                if (MetadataHelper.TryGetFunctionImportReturnType <ComplexType>(functionImport, 0, out returnType2))
                {
                    List <PropertyMapping> propertyMappings;
                    if (!this.TryConvertToPropertyMappings((StructuralType)returnType2, cTypeTvfElementType, sTypeTvfElementType, functionImport, functionImportKB, lineInfo, out propertyMappings))
                    {
                        return(false);
                    }
                    structuralTypeMappings.Add(Tuple.Create <StructuralType, List <ConditionPropertyMapping>, List <PropertyMapping> >((StructuralType)returnType2, new List <ConditionPropertyMapping>(), propertyMappings));
                }
            }
            mapping = new FunctionImportMappingComposable(functionImport, cTypeTargetFunction, structuralTypeMappings, keys, this._entityContainerMapping);
            return(true);
        }
        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());
        }
Ejemplo n.º 20
0
        public void WriteFunctionImportMappingElement_does_not_write_result_mapping_when_result_mapped_to_primitive_type()
        {
            var typeUsage =
                TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32));

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

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

            var storeFunction =
                new EdmFunction(
                    "f_s", "Ns.Store", DataSpace.SSpace,
                    new EdmFunctionPayload
                    {
                        ReturnParameters =
                            new[]
                                    {
                                        new FunctionParameter(
                                            "Return",
                                            TypeUsage.CreateDefaultTypeUsage(rowType.GetCollectionType()),
                                            ParameterMode.ReturnValue)
                                    },
                    });
            
            var functionImportMapping = new FunctionImportMappingComposable(
                functionImport,
                storeFunction,
                new FunctionImportResultMapping(),
                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 bool TryCreateFunctionImportMappingComposableWithStructuralResult(
            EdmFunction functionImport,
            EdmFunction cTypeTargetFunction,
            List<FunctionImportStructuralTypeMapping> typeMappings,
            RowType cTypeTvfElementType,
            RowType sTypeTvfElementType,
            IXmlLineInfo lineInfo,
            out FunctionImportMappingComposable mapping)
        {
            mapping = null;

            // If it is an implicit structural type mapping, add a type mapping fragment for the return type of the function import,
            // unless it is an abstract type.
            if (typeMappings.Count == 0)
            {
                StructuralType resultType;
                if (MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultType))
                {
                    if (resultType.Abstract)
                    {
                        AddToSchemaErrorWithMemberAndStructure(
                            Strings.Mapping_FunctionImport_ImplicitMappingForAbstractReturnType,
                            resultType.FullName, functionImport.Identity,
                            MappingErrorCode.MappingOfAbstractType, m_sourceLocation, lineInfo, m_parsingErrors);
                        return false;
                    }
                    if (resultType.BuiltInTypeKind
                        == BuiltInTypeKind.EntityType)
                    {
                        typeMappings.Add(
                            new FunctionImportEntityTypeMapping(
                                Enumerable.Empty<EntityType>(),
                                new[] { (EntityType)resultType },
                                Enumerable.Empty<FunctionImportEntityTypeMappingCondition>(),
                                new Collection<FunctionImportReturnTypePropertyMapping>(),
                                new LineInfo(lineInfo)));
                    }
                    else
                    {
                        Debug.Assert(
                            resultType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                            "resultType.BuiltInTypeKind == BuiltInTypeKind.ComplexType");
                        typeMappings.Add(
                            new FunctionImportComplexTypeMapping(
                                (ComplexType)resultType,
                                new Collection<FunctionImportReturnTypePropertyMapping>(),
                                new LineInfo(lineInfo)));
                    }
                }
            }


            // 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 provide an empty EdmItemCollection which
            // will allow inferring implicit result mapping
            var edmItemCollection =
                _entityContainerMapping.StorageMappingItemCollection != null
                    ? _entityContainerMapping.StorageMappingItemCollection.EdmItemCollection
                    : new EdmItemCollection(new EdmModel(DataSpace.CSpace));

            // Validate and convert FunctionImportEntityTypeMapping elements into structure suitable for composable function import mapping.
            var functionImportKB = new FunctionImportStructuralTypeMappingKB(typeMappings, edmItemCollection);

            var structuralTypeMappings =
                new List<Tuple<StructuralType, List<ConditionPropertyMapping>, List<PropertyMapping>>>();
            EdmProperty[] targetFunctionKeys = null;
            if (functionImportKB.MappedEntityTypes.Count > 0)
            {
                // Validate TPH ambiguity.
                if (!functionImportKB.ValidateTypeConditions( /*validateAmbiguity: */true, m_parsingErrors, m_sourceLocation))
                {
                    return false;
                }

                // For each mapped entity type, prepare list of conditions and list of property mappings.
                for (var i = 0; i < functionImportKB.MappedEntityTypes.Count; ++i)
                {
                    List<ConditionPropertyMapping> typeConditions;
                    List<PropertyMapping> propertyMappings;
                    if (TryConvertToEntityTypeConditionsAndPropertyMappings(
                        functionImport,
                        functionImportKB,
                        i,
                        cTypeTvfElementType,
                        sTypeTvfElementType,
                        lineInfo, out typeConditions, out propertyMappings))
                    {
                        structuralTypeMappings.Add(
                            Tuple.Create((StructuralType)functionImportKB.MappedEntityTypes[i], typeConditions, propertyMappings));
                    }
                }
                if (structuralTypeMappings.Count
                    < functionImportKB.MappedEntityTypes.Count)
                {
                    // Some of the entity types produced errors during conversion, exit.
                    return false;
                }

                // Infer target function keys based on the c-space entity types.
                if (!TryInferTVFKeys(structuralTypeMappings, out targetFunctionKeys))
                {
                    AddToSchemaErrorsWithMemberInfo(
                        Strings.Mapping_FunctionImport_CannotInferTargetFunctionKeys, functionImport.Identity,
                        MappingErrorCode.MappingFunctionImportCannotInferTargetFunctionKeys, m_sourceLocation, lineInfo,
                        m_parsingErrors);
                    return false;
                }
            }
            else
            {
                ComplexType resultComplexType;
                if (MetadataHelper.TryGetFunctionImportReturnType(functionImport, 0, out resultComplexType))
                {
                    // Gather and validate complex type property mappings.
                    List<PropertyMapping> propertyMappings;
                    if (
                        !TryConvertToPropertyMappings(
                            resultComplexType, cTypeTvfElementType, sTypeTvfElementType, functionImport, functionImportKB, lineInfo,
                            out propertyMappings))
                    {
                        return false;
                    }
                    structuralTypeMappings.Add(
                        Tuple.Create((StructuralType)resultComplexType, new List<ConditionPropertyMapping>(), propertyMappings));
                }
                else
                {
                    Debug.Fail("Function import return type is expected to be a collection of complex type.");
                }
            }

            mapping = new FunctionImportMappingComposable(
                functionImport,
                cTypeTargetFunction,
                structuralTypeMappings,
                targetFunctionKeys,
                _entityContainerMapping);
            return true;
        }
        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 Can_add_and_get_function_import_mapping()
        {
            var typeUsage = 
                TypeUsage.CreateDefaultTypeUsage(
                    PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32).GetCollectionType());

            var entityContainerMapping = new EntityContainerMapping(new EntityContainer("C", DataSpace.CSpace));

            var composableFuntionMapping =
                new FunctionImportMappingComposable(
                    new EdmFunction(
                        "f", "model", DataSpace.CSpace,
                        new EdmFunctionPayload()
                            {
                                IsComposable = true,
                                ReturnParameters =
                                    new[]
                                        {
                                            new FunctionParameter(
                                                "ReturnType",
                                                typeUsage,
                                                ParameterMode.ReturnValue),
                                        }

                            }),
                    new EdmFunction(
                        "f", "store", DataSpace.SSpace,
                        new EdmFunctionPayload()
                            {
                                IsComposable = true,
                                ReturnParameters =
                                    new[]
                                        {
                                            new FunctionParameter(
                                                "ReturnType",
                                                typeUsage,
                                                ParameterMode.ReturnValue),
                                        }
                            }),
                    null);

            Assert.Empty(entityContainerMapping.FunctionImportMappings);
            entityContainerMapping.AddFunctionImportMapping(composableFuntionMapping);
            Assert.Same(composableFuntionMapping, entityContainerMapping.FunctionImportMappings.Single());
        }
        internal bool TryCreateFunctionImportMappingComposableWithScalarResult(
            EdmFunction functionImport,
            EdmFunction cTypeTargetFunction,
            EdmFunction sTypeTargetFunction,
            EdmType scalarResultType,
            RowType cTypeTvfElementType,
            IXmlLineInfo lineInfo,
            out FunctionImportMappingComposable mapping)
        {
            mapping = null;

            // Make sure that TVF returns exactly one column
            if (cTypeTvfElementType.Properties.Count > 1)
            {
                AddToSchemaErrors(
                    Strings.Mapping_FunctionImport_ScalarMappingToMulticolumnTVF(functionImport.Identity, sTypeTargetFunction.Identity),
                    MappingErrorCode.MappingFunctionImportScalarMappingToMulticolumnTVF, m_sourceLocation, lineInfo, m_parsingErrors);
                return false;
            }

            // Make sure that scalarResultType agrees with the column type.
            if (
                !ValidateFunctionImportMappingResultTypeCompatibility(
                    TypeUsage.Create(scalarResultType), cTypeTvfElementType.Properties[0].TypeUsage))
            {
                AddToSchemaErrors(
                    Strings.Mapping_FunctionImport_ScalarMappingTypeMismatch(
                        functionImport.ReturnParameter.TypeUsage.EdmType.FullName,
                        functionImport.Identity,
                        sTypeTargetFunction.ReturnParameter.TypeUsage.EdmType.FullName,
                        sTypeTargetFunction.Identity),
                    MappingErrorCode.MappingFunctionImportScalarMappingTypeMismatch, m_sourceLocation, lineInfo, m_parsingErrors);
                return false;
            }

            mapping = new FunctionImportMappingComposable(
                functionImport,
                cTypeTargetFunction,
                null,
                null,
                _entityContainerMapping);
            return true;
        }
Ejemplo n.º 25
0
 private static DbExpression GenerateStructuralTypeConditionsPredicate(
     List <ConditionPropertyMapping> conditions,
     DbExpression row)
 {
     return(Helpers.BuildBalancedTreeInPlace <DbExpression>((IList <DbExpression>)conditions.Select <ConditionPropertyMapping, DbExpression>((Func <ConditionPropertyMapping, DbExpression>)(c => FunctionImportMappingComposable.GeneratePredicate(c, row))).ToArray <DbExpression>(), (Func <DbExpression, DbExpression, DbExpression>)((prev, next) => (DbExpression)prev.And(next))));
 }
        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_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);
        }