public void Create_factory_method_sets_properties_and_seals_the_type() { var rowType = RowType.Create( new[] { EdmProperty.Primitive("foo", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), EdmProperty.Primitive("bar", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int64)) }, new[] { new MetadataProperty( "TestProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "baz") } ); Assert.NotNull(rowType); Assert.Equal(new[] { "foo", "bar" }, rowType.Properties.Select(p => p.Name)); var metadataProperty = rowType.MetadataProperties.SingleOrDefault(p => p.Name == "TestProperty"); Assert.NotNull(metadataProperty); Assert.Equal("baz", metadataProperty.Value); Assert.True(rowType.IsReadOnly); }
internal override bool EdmEquals(MetadataItem item) { if (object.ReferenceEquals((object)this, (object)item)) { return(true); } if (item == null || BuiltInTypeKind.RowType != item.BuiltInTypeKind) { return(false); } RowType rowType = (RowType)item; if (this.Members.Count != rowType.Members.Count) { return(false); } for (int index = 0; index < this.Members.Count; ++index) { EdmMember member1 = this.Members[index]; EdmMember member2 = rowType.Members[index]; if (!member1.EdmEquals((MetadataItem)member2) || !member1.TypeUsage.EdmEquals((MetadataItem)member2.TypeUsage)) { return(false); } } return(true); }
public void EdmModel_NameIsTooLong_not_triggered_for_row_and_collection_types() { var intType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32); var properties = new EdmProperty[100]; for (int i = 0; i < 100; i++) { properties[i] = EdmProperty.Primitive("Property" + i, intType); } var rowType = new RowType(properties); foreach (var type in new EdmType[] { rowType, rowType.GetCollectionType() }) { var validationContext = new EdmModelValidationContext(new EdmModel(DataSpace.SSpace), true); DataModelErrorEventArgs errorEventArgs = null; validationContext.OnError += (_, e) => errorEventArgs = e; EdmModelSyntacticValidationRules .EdmModel_NameIsTooLong .Evaluate(validationContext, type); Assert.Null(errorEventArgs); } }
private static bool TryGetCommonType(RowType rowType1, RowType rowType2, out EdmType commonRowType) { if (rowType1.Properties.Count != rowType2.Properties.Count || rowType1.InitializerMetadata != rowType2.InitializerMetadata) { commonRowType = null; return(false); } // find a common type for every property var commonProperties = new List <EdmProperty>(); for (var i = 0; i < rowType1.Properties.Count; i++) { TypeUsage columnCommonTypeUsage; if (!TryGetCommonType(rowType1.Properties[i].TypeUsage, rowType2.Properties[i].TypeUsage, out columnCommonTypeUsage)) { commonRowType = null; return(false); } commonProperties.Add(new EdmProperty(rowType1.Properties[i].Name, columnCommonTypeUsage)); } commonRowType = new RowType(commonProperties, rowType1.InitializerMetadata); return(true); }
/// <summary> /// Create a new VarInfo for a structured type Var /// </summary> /// <param name="v"> The structured type Var </param> /// <param name="newType"> "Mapped" type for v </param> /// <param name="newVars"> List of vars corresponding to v </param> /// <param name="newProperties"> Flattened Properties </param> /// <param name="newVarsIncludeNullSentinelVar"> Do the new vars include a var that represents a null sentinel either for this type or for any nested type </param> /// <returns> the VarInfo </returns> internal VarInfo CreateStructuredVarInfo( Var v, RowType newType, List<Var> newVars, List<EdmProperty> newProperties, bool newVarsIncludeNullSentinelVar) { VarInfo varInfo = new StructuredVarInfo(newType, newVars, newProperties, newVarsIncludeNullSentinelVar); m_map.Add(v, varInfo); return varInfo; }
private static bool TryGetCommonType( RowType rowType1, RowType rowType2, out EdmType commonRowType) { if (rowType1.Properties.Count != rowType2.Properties.Count || rowType1.InitializerMetadata != rowType2.InitializerMetadata) { commonRowType = (EdmType)null; return(false); } List <EdmProperty> edmPropertyList = new List <EdmProperty>(); for (int index = 0; index < rowType1.Properties.Count; ++index) { TypeUsage commonType; if (!TypeSemantics.TryGetCommonType(rowType1.Properties[index].TypeUsage, rowType2.Properties[index].TypeUsage, out commonType)) { commonRowType = (EdmType)null; return(false); } edmPropertyList.Add(new EdmProperty(rowType1.Properties[index].Name, commonType)); } commonRowType = (EdmType) new RowType((IEnumerable <EdmProperty>)edmPropertyList, rowType1.InitializerMetadata); return(true); }
public void EdmModel_NameIsTooLong_not_triggered_for_row_and_collection_types() { var intType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32); var properties = new EdmProperty[100]; for (int i = 0; i < 100; i++) { properties[i] = EdmProperty.CreatePrimitive("Property" + i, intType); } var rowType = new RowType(properties); foreach (var type in new EdmType[] { rowType, rowType.GetCollectionType() }) { var validationContext = new EdmModelValidationContext(new EdmModel(DataSpace.SSpace), true); DataModelErrorEventArgs errorEventArgs = null; validationContext.OnError += (_, e) => errorEventArgs = e; EdmModelSyntacticValidationRules .EdmModel_NameIsTooLong .Evaluate(validationContext, type); Assert.Null(errorEventArgs); } }
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 StructuredVarInfo( RowType newType, List<Var> newVars, List<EdmProperty> newTypeProperties, bool newVarsIncludeNullSentinelVar) { PlanCompiler.Assert(newVars.Count == newTypeProperties.Count, "count mismatch"); // I see a few places where this is legal // PlanCompiler.Assert(newVars.Count > 0, "0 vars?"); m_newVars = newVars; m_newProperties = newTypeProperties; m_newType = newType; m_newVarsIncludeNullSentinelVar = newVarsIncludeNullSentinelVar; m_newTypeUsage = TypeUsage.Create(newType); }
internal RowType(IEnumerable <EdmProperty> properties, InitializerMetadata initializerMetadata) : base(RowType.GetRowTypeIdentityFromProperties(RowType.CheckProperties(properties), initializerMetadata), "Transient", ~DataSpace.OSpace) { if (properties != null) { foreach (EdmProperty property in properties) { this.AddProperty(property); } } this._initializerMetadata = initializerMetadata; this.SetReadOnly(); }
public void Can_get_list_of_declared_properties() { var rowType = new RowType(); Assert.Empty(rowType.DeclaredProperties); var property = EdmProperty.Primitive("P", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); rowType.AddMember(property); Assert.Equal(1, rowType.DeclaredProperties.Count); rowType.RemoveMember(property); }
/// <summary> /// The factory method for constructing the <see cref="T:System.Data.Entity.Core.Metadata.Edm.RowType" /> object. /// </summary> /// <param name="properties">Properties of the row type object.</param> /// <param name="metadataProperties">Metadata properties that will be added to the function. Can be null.</param> /// <returns> /// A new, read-only instance of the <see cref="T:System.Data.Entity.Core.Metadata.Edm.RowType" /> object. /// </returns> public static RowType Create( IEnumerable <EdmProperty> properties, IEnumerable <MetadataProperty> metadataProperties) { Check.NotNull <IEnumerable <EdmProperty> >(properties, nameof(properties)); RowType rowType = new RowType(properties); if (metadataProperties != null) { rowType.AddMetadataProperties(metadataProperties.ToList <MetadataProperty>()); } rowType.SetReadOnly(); return(rowType); }
public void Can_get_list_of_declared_properties() { var rowType = new RowType(); Assert.Empty(rowType.DeclaredProperties); var property = EdmProperty.CreatePrimitive("P", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); rowType.AddMember(property); Assert.Equal(1, rowType.DeclaredProperties.Count); rowType.RemoveMember(property); }
public void Cannot_create_property_of_invalid_type() { var rowType = RowType.Create( new[] { EdmProperty.Primitive("property", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }, null); Assert.Equal( Strings.EdmProperty_InvalidPropertyType(rowType.FullName), Assert.Throws <ArgumentException>(() => EdmProperty.Create("invalidProperty", TypeUsage.Create(rowType))).Message); }
/// <summary> /// The factory method for constructing the <see cref="RowType" /> object. /// </summary> /// <param name="properties">Properties of the row type object.</param> /// <param name="metadataProperties">Metadata properties that will be added to the function. Can be null.</param> /// <returns> /// A new, read-only instance of the <see cref="RowType" /> object. /// </returns> public static RowType Create(IEnumerable <EdmProperty> properties, IEnumerable <MetadataProperty> metadataProperties) { Check.NotNull(properties, "properties"); var rowType = new RowType(properties); if (metadataProperties != null) { rowType.AddMetadataProperties(metadataProperties); } rowType.SetReadOnly(); return(rowType); }
private static bool IsPromotableTo(RowType fromRowType, RowType toRowType) { if (fromRowType.Properties.Count != toRowType.Properties.Count) { return(false); } for (int index = 0; index < fromRowType.Properties.Count; ++index) { if (!TypeSemantics.IsPromotableTo(fromRowType.Properties[index].TypeUsage, toRowType.Properties[index].TypeUsage)) { return(false); } } return(true); }
public void EdmModel_NameIsNotAllowed_not_triggered_for_row_and_collection_types() { var rowType = new RowType(new[] { EdmProperty.CreatePrimitive("Property", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }); foreach (var type in new EdmType[] { rowType, rowType.GetCollectionType() }) { var validationContext = new EdmModelValidationContext(new EdmModel(DataSpace.SSpace), true); DataModelErrorEventArgs errorEventArgs = null; validationContext.OnError += (_, e) => errorEventArgs = e; EdmModelSyntacticValidationRules .EdmModel_NameIsNotAllowed .Evaluate(validationContext, type); Assert.Null(errorEventArgs); } }
public void EdmModel_NameIsNotAllowed_not_triggered_for_row_and_collection_types() { var rowType = new RowType(new[] { EdmProperty.Primitive("Property", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }); foreach (var type in new EdmType[] { rowType, rowType.GetCollectionType() }) { var validationContext = new EdmModelValidationContext(new EdmModel(DataSpace.SSpace), true); DataModelErrorEventArgs errorEventArgs = null; validationContext.OnError += (_, e) => errorEventArgs = e; EdmModelSyntacticValidationRules .EdmModel_NameIsNotAllowed .Evaluate(validationContext, type); Assert.Null(errorEventArgs); } }
public void CSpace_RowType_returned_for_SSpace_RowType() { var sSpaceTypeUsage = FakeSqlProviderServices .Instance.GetProviderManifest("2008") .GetStoreType(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String))); var sSpaceRowTypeUsage = TypeUsage.CreateDefaultTypeUsage(RowType.Create(new[] { EdmProperty.Create("foo", sSpaceTypeUsage) }, null)); var cSpaceRowType = (RowType)sSpaceRowTypeUsage.ModelTypeUsage.EdmType; Assert.Equal(DataSpace.CSpace, cSpaceRowType.GetDataSpace()); Assert.Equal(1, cSpaceRowType.Properties.Count); Assert.Equal(DataSpace.CSpace, cSpaceRowType.Properties.Single().TypeUsage.EdmType.GetDataSpace()); Assert.Equal("foo", cSpaceRowType.Properties.Single().Name); Assert.Equal( PrimitiveTypeKind.String, ((PrimitiveType)cSpaceRowType.Properties.Single().TypeUsage.EdmType).PrimitiveTypeKind); }
private static bool IsPromotableTo(RowType fromRowType, RowType toRowType) { DebugCheck.NotNull(fromRowType); DebugCheck.NotNull(toRowType); if (fromRowType.Properties.Count != toRowType.Properties.Count) { return(false); } for (var i = 0; i < fromRowType.Properties.Count; i++) { if (!IsPromotableTo(fromRowType.Properties[i].TypeUsage, toRowType.Properties[i].TypeUsage)) { return(false); } } return(true); }
private static bool CompareTypes(TypeUsage fromType, TypeUsage toType, bool equivalenceOnly) { if (object.ReferenceEquals((object)fromType, (object)toType)) { return(true); } if (fromType.EdmType.BuiltInTypeKind != toType.EdmType.BuiltInTypeKind) { return(false); } if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType) { return(TypeSemantics.CompareTypes(((CollectionType)fromType.EdmType).TypeUsage, ((CollectionType)toType.EdmType).TypeUsage, equivalenceOnly)); } if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType) { return(((RefType)fromType.EdmType).ElementType.EdmEquals((MetadataItem)((RefType)toType.EdmType).ElementType)); } if (fromType.EdmType.BuiltInTypeKind != BuiltInTypeKind.RowType) { return(fromType.EdmType.EdmEquals((MetadataItem)toType.EdmType)); } RowType edmType1 = (RowType)fromType.EdmType; RowType edmType2 = (RowType)toType.EdmType; if (edmType1.Properties.Count != edmType2.Properties.Count) { return(false); } for (int index = 0; index < edmType1.Properties.Count; ++index) { EdmProperty property1 = edmType1.Properties[index]; EdmProperty property2 = edmType2.Properties[index]; if (!equivalenceOnly && property1.Name != property2.Name || !TypeSemantics.CompareTypes(property1.TypeUsage, property2.TypeUsage, equivalenceOnly)) { return(false); } } return(true); }
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 WriteFunctionImportMappingElement_writes_result_mapping_for_non_composable_functions_mapped_explicitly_to_EntityType() { var typeUsage = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); var entityTypeProperty1 = new EdmProperty("ETProperty1", typeUsage); var entityTypeProperty2 = new EdmProperty("ETProperty2", typeUsage); var entityType = new EntityType("ET", "Ns", DataSpace.CSpace); entityType.AddMember(entityTypeProperty1); entityType.AddMember(entityTypeProperty2); var functionImport = new EdmFunction( "f_c", "Ns", DataSpace.CSpace, new EdmFunctionPayload { IsComposable = false, IsFunctionImport = true, ReturnParameters = new[] { new FunctionParameter( "ReturnValue", TypeUsage.CreateDefaultTypeUsage(entityType.GetCollectionType()), ParameterMode.ReturnValue) }, }); typeUsage = ProviderRegistry.Sql2008_ProviderManifest.GetStoreType(typeUsage); var rowTypeProperty1 = new EdmProperty("RTProperty1", typeUsage); var rowTypeProperty2 = new EdmProperty("RTProperty2", typeUsage); var rowType = new RowType(new[] { rowTypeProperty1, rowTypeProperty2 }); var storeFunction = new EdmFunction( "f_s", "Ns.Store", DataSpace.SSpace, new EdmFunctionPayload { IsComposable = false, ReturnParameters = new[] { new FunctionParameter( "Return", TypeUsage.CreateDefaultTypeUsage(rowType), ParameterMode.ReturnValue) }, }); var functionImportResultMapping = new FunctionImportResultMapping(); functionImportResultMapping.AddTypeMapping( new FunctionImportEntityTypeMapping( new EntityType[0], new [] { entityType }, new Collections.ObjectModel.Collection<FunctionImportReturnTypePropertyMapping>() { new FunctionImportReturnTypeScalarPropertyMapping("ETProperty1", "RTProperty1"), new FunctionImportReturnTypeScalarPropertyMapping("ETProperty2", "RTProperty2") }, new FunctionImportEntityTypeMappingCondition[] { new FunctionImportEntityTypeMappingConditionIsNull("RTProperty1", false), new FunctionImportEntityTypeMappingConditionValue("RTProperty2", 4), new FunctionImportEntityTypeMappingConditionValue("FakeCondition", true) } )); var mappingItemCollection = new StorageMappingItemCollection( new EdmItemCollection(EdmModel.CreateConceptualModel()), new StoreItemCollection( EdmModel.CreateStoreModel(ProviderRegistry.Sql2008_ProviderInfo, ProviderRegistry.Sql2008_ProviderManifest)), new string[0]); var containerMapping = new EntityContainerMapping( new EntityContainer("C", DataSpace.CSpace), new EntityContainer("S", DataSpace.SSpace), mappingItemCollection, false); var functionImportMapping = new FunctionImportMappingNonComposable( functionImport, storeFunction, new [] { functionImportResultMapping }, containerMapping); containerMapping.AddFunctionImportMapping(functionImportMapping); var fixture = new Fixture(); fixture.Writer.WriteFunctionImportMappingElement(functionImportMapping); Assert.Equal( @"<FunctionImportMapping FunctionName=""Ns.Store.f_s"" FunctionImportName=""f_c""> <ResultMapping> <EntityTypeMapping TypeName=""Ns.ET""> <ScalarProperty Name=""ETProperty1"" ColumnName=""RTProperty1"" /> <ScalarProperty Name=""ETProperty2"" ColumnName=""RTProperty2"" /> <Condition ColumnName=""RTProperty1"" IsNull=""false"" /> <Condition ColumnName=""RTProperty2"" Value=""4"" /> <Condition ColumnName=""FakeCondition"" Value=""1"" /> </EntityTypeMapping> </ResultMapping> </FunctionImportMapping>", fixture.ToString()); }
public void WriteFunctionImportMappingElement_does_not_write_result_mapping_for_non_composable_functions_mapped_implicitly() { var typeUsage = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); var complexTypeProperty1 = new EdmProperty("CTProperty1", typeUsage); var complexTypeProperty2 = new EdmProperty("CTProperty2", typeUsage); var complexType = new ComplexType("CT", "Ns", DataSpace.CSpace); complexType.AddMember(complexTypeProperty1); complexType.AddMember(complexTypeProperty2); var functionImport = new EdmFunction( "f_c", "Ns", DataSpace.CSpace, new EdmFunctionPayload { IsComposable = false, IsFunctionImport = true, ReturnParameters = new[] { new FunctionParameter( "ReturnValue", TypeUsage.CreateDefaultTypeUsage(complexType.GetCollectionType()), ParameterMode.ReturnValue) }, }); typeUsage = ProviderRegistry.Sql2008_ProviderManifest.GetStoreType(typeUsage); var rowTypeProperty1 = new EdmProperty("RTProperty1", typeUsage); var rowTypeProperty2 = new EdmProperty("RTProperty2", typeUsage); var rowType = new RowType(new[] { rowTypeProperty1, rowTypeProperty2 }); var storeFunction = new EdmFunction( "f_s", "Ns.Store", DataSpace.SSpace, new EdmFunctionPayload { IsComposable = false, ReturnParameters = new[] { new FunctionParameter( "Return", TypeUsage.CreateDefaultTypeUsage(rowType), ParameterMode.ReturnValue) }, }); var functionImportMapping = new FunctionImportMappingNonComposable( functionImport, storeFunction, new FunctionImportResultMapping[0], new EntityContainerMapping(new EntityContainer("C", DataSpace.SSpace))); var fixture = new Fixture(); fixture.Writer.WriteFunctionImportMappingElement(functionImportMapping); Assert.Equal( @"<FunctionImportMapping FunctionName=""Ns.Store.f_s"" FunctionImportName=""f_c"" />", fixture.ToString()); }
// <summary> // Create a "flat" table definition object (ie) the table has one column // for each property of the specified row type // </summary> // <param name="type"> the shape of each row of the table </param> // <returns> the table definition </returns> internal virtual TableMD CreateFlatTableDefinition(RowType type) { return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null); }
private void AddSpannedRowType(RowType spannedType, TypeUsage originalType) { if (null == _spanIndex) { _spanIndex = new SpanIndex(); } _spanIndex.AddSpannedRowType(spannedType, originalType); }
protected internal override void VisitRowType(RowType rowType) { this._schemaWriter.WriteRowTypeElementHeader(); base.VisitRowType(rowType); this._schemaWriter.WriteEndElement(); }
private void AddSpanMap(RowType rowType, Dictionary<int, AssociationEndMember> columnMap) { if (null == _spanIndex) { _spanIndex = new SpanIndex(); } _spanIndex.AddSpanMap(rowType, columnMap); }
private bool TryConvertToEntityTypeConditionsAndPropertyMappings( EdmFunction functionImport, FunctionImportStructuralTypeMappingKB functionImportKB, int typeID, RowType cTypeTvfElementType, RowType sTypeTvfElementType, IXmlLineInfo navLineInfo, out List<ConditionPropertyMapping> typeConditions, out List<PropertyMapping> propertyMappings) { var entityType = functionImportKB.MappedEntityTypes[typeID]; typeConditions = new List<ConditionPropertyMapping>(); var errorFound = false; // Gather and validate entity type conditions from the type-producing fragments. foreach (var entityTypeMapping in functionImportKB.NormalizedEntityTypeMappings.Where(f => f.ImpliedEntityTypes[typeID])) { foreach (var condition in entityTypeMapping.ColumnConditions.Where(c => c != null)) { EdmProperty column; if (sTypeTvfElementType.Properties.TryGetValue(condition.ColumnName, false, out column)) { object value; bool? isNull; if (condition.ConditionValue.IsSentinel) { value = null; if (condition.ConditionValue == ValueCondition.IsNull) { isNull = true; } else { Debug.Assert( condition.ConditionValue == ValueCondition.IsNotNull, "Only IsNull or IsNotNull condition values are expected."); isNull = false; } } else { var cTypeColumn = cTypeTvfElementType.Properties[column.Name]; Debug.Assert(cTypeColumn != null, "cTypeColumn != null"); Debug.Assert( Helper.IsPrimitiveType(cTypeColumn.TypeUsage.EdmType), "S-space columns are expected to be of a primitive type."); var cPrimitiveType = (PrimitiveType)cTypeColumn.TypeUsage.EdmType; Debug.Assert(cPrimitiveType.ClrEquivalentType != null, "Scalar Types should have associated clr type"); Debug.Assert( condition is FunctionImportEntityTypeMappingConditionValue, "Non-sentinel condition is expected to be of type FunctionImportEntityTypeMappingConditionValue."); value = ((FunctionImportEntityTypeMappingConditionValue)condition).GetConditionValue( cPrimitiveType.ClrEquivalentType, handleTypeNotComparable: () => { AddToSchemaErrorWithMemberAndStructure( Strings. Mapping_InvalidContent_ConditionMapping_InvalidPrimitiveTypeKind, column.Name, column.TypeUsage.EdmType.FullName, MappingErrorCode.ConditionError, m_sourceLocation, condition.LineInfo, m_parsingErrors); }, handleInvalidConditionValue: () => { AddToSchemaErrors( Strings.Mapping_ConditionValueTypeMismatch, MappingErrorCode.ConditionError, m_sourceLocation, condition.LineInfo, m_parsingErrors); }); if (value == null) { errorFound = true; continue; } isNull = null; } typeConditions.Add(new ConditionPropertyMapping(null, column, value, isNull)); } else { AddToSchemaErrorsWithMemberInfo( Strings.Mapping_InvalidContent_Column, condition.ColumnName, MappingErrorCode.InvalidStorageMember, m_sourceLocation, condition.LineInfo, m_parsingErrors); } } } // Gather and validate entity type property mappings. errorFound |= !TryConvertToPropertyMappings( entityType, cTypeTvfElementType, sTypeTvfElementType, functionImport, functionImportKB, navLineInfo, out propertyMappings); return !errorFound; }
private static void VerifyRowTypeSupportedForComparison(Type clrType, RowType rowType, Stack<EdmMember> memberPath) { foreach (EdmMember member in rowType.Properties) { if (null == memberPath) { memberPath = new Stack<EdmMember>(); } memberPath.Push(member); VerifyTypeSupportedForComparison(clrType, member.TypeUsage, memberPath); memberPath.Pop(); } }
internal override TypeUsage GetTypeUsage() { if (_typeUsage == null) { var listOfProperties = new List<EdmProperty>(); foreach (var property in _properties) { var edmProperty = new EdmProperty(property.FQName, property.GetTypeUsage()); edmProperty.AddMetadataProperties(property.OtherContent); //edmProperty.DeclaringType listOfProperties.Add(edmProperty); } var rowType = new RowType(listOfProperties); if (Schema.DataModel == SchemaDataModelOption.EntityDataModel) { rowType.DataSpace = DataSpace.CSpace; } else { Debug.Assert( Schema.DataModel == SchemaDataModelOption.ProviderDataModel, "Only DataModel == SchemaDataModelOption.ProviderDataModel is expected"); rowType.DataSpace = DataSpace.SSpace; } rowType.AddMetadataProperties(OtherContent); _typeUsage = TypeUsage.Create(rowType); } return _typeUsage; }
// <summary> // Determines the expected shape of store results. We expect a column for every property // of the mapped type (or types) and a column for every discriminator column. We make no // assumptions about the order of columns: the provider is expected to determine appropriate // types by looking at the names of the result columns, not the order of columns, which is // different from the typical handling of row types in the EF. // </summary> // <remarks> // Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL // function. // </remarks> // <returns> Row type. </returns> internal TypeUsage GetExpectedTargetResultType(int resultSetIndex) { var resultMapping = GetResultMapping(resultSetIndex); // Collect all columns as name-type pairs. var columns = new Dictionary<string, TypeUsage>(); // Figure out which entity types we expect to yield from the function. IEnumerable<StructuralType> structuralTypes; if (0 == resultMapping.NormalizedEntityTypeMappings.Count) { // No explicit type mappings; just use the type specified in the ReturnType attribute on the function. StructuralType structuralType; MetadataHelper.TryGetFunctionImportReturnType(FunctionImport, resultSetIndex, out structuralType); Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); structuralTypes = new[] { structuralType }; } else { // Types are explicitly mapped. structuralTypes = resultMapping.MappedEntityTypes.Cast<StructuralType>(); } // Gather columns corresponding to all properties. foreach (var structuralType in structuralTypes) { foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // NOTE: if a complex type is encountered, the column map generator will // throw. For now, we just let them through. // We expect to see each property multiple times, so we use indexer rather than // .Add. columns[property.Name] = property.TypeUsage; } } // Gather discriminator columns. foreach (var discriminatorColumn in GetDiscriminatorColumns(resultSetIndex)) { if (!columns.ContainsKey(discriminatorColumn)) { // CONSIDER: we assume that discriminatorColumns are all string types. In practice, // we're flexible about the runtime type during materialization, so the provider's // decision is hopefully irrelevant. The alternative is to require typed stored // procedure declarations in the SSDL, which is too much of a burden on the user and/or the // tools (there is no reliable way of determining this metadata automatically from SQL // Server). var type = TypeUsage.CreateStringTypeUsage( MetadataWorkspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); columns.Add(discriminatorColumn, type); } } // Expected type is a collection of rows var rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); var result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType))); return result; }
private bool TryConvertToPropertyMappings( StructuralType structuralType, RowType cTypeTvfElementType, RowType sTypeTvfElementType, EdmFunction functionImport, FunctionImportStructuralTypeMappingKB functionImportKB, IXmlLineInfo navLineInfo, out List<PropertyMapping> propertyMappings) { propertyMappings = new List<PropertyMapping>(); // Gather and validate structuralType property mappings. var errorFound = false; foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // Only scalar property mappings are supported at the moment. if (!Helper.IsScalarType(property.TypeUsage.EdmType)) { var error = new EdmSchemaError( Strings.Mapping_Invalid_CSide_ScalarProperty(property.Name), (int)MappingErrorCode.InvalidTypeInScalarProperty, EdmSchemaErrorSeverity.Error, m_sourceLocation, navLineInfo.LineNumber, navLineInfo.LinePosition); m_parsingErrors.Add(error); errorFound = true; continue; } string columnName = null; IXmlLineInfo columnMappingLineInfo = null; FunctionImportReturnTypeStructuralTypeColumnRenameMapping columnRenameMapping; bool explicitPropertyMapping; if (functionImportKB.ReturnTypeColumnsRenameMapping.TryGetValue(property.Name, out columnRenameMapping)) { explicitPropertyMapping = true; columnName = columnRenameMapping.GetRename(structuralType, out columnMappingLineInfo); } else { explicitPropertyMapping = false; columnName = property.Name; } columnMappingLineInfo = columnMappingLineInfo != null && columnMappingLineInfo.HasLineInfo() ? columnMappingLineInfo : navLineInfo; EdmProperty column; if (sTypeTvfElementType.Properties.TryGetValue(columnName, false, out column)) { Debug.Assert(cTypeTvfElementType.Properties.Contains(columnName), "cTypeTvfElementType.Properties.Contains(columnName)"); var cTypeColumn = cTypeTvfElementType.Properties[columnName]; if (ValidateFunctionImportMappingResultTypeCompatibility(property.TypeUsage, cTypeColumn.TypeUsage)) { propertyMappings.Add(new ScalarPropertyMapping(property, column)); } else { var error = new EdmSchemaError( GetInvalidMemberMappingErrorMessage(property, column), (int)MappingErrorCode.IncompatibleMemberMapping, EdmSchemaErrorSeverity.Error, m_sourceLocation, columnMappingLineInfo.LineNumber, columnMappingLineInfo.LinePosition); m_parsingErrors.Add(error); errorFound = true; } } else { if (explicitPropertyMapping) { AddToSchemaErrorsWithMemberInfo( Strings.Mapping_InvalidContent_Column, columnName, MappingErrorCode.InvalidStorageMember, m_sourceLocation, columnMappingLineInfo, m_parsingErrors); errorFound = true; } else { var error = new EdmSchemaError( Strings.Mapping_FunctionImport_PropertyNotMapped( property.Name, structuralType.FullName, functionImport.Identity), (int)MappingErrorCode.MappingFunctionImportReturnTypePropertyNotMapped, EdmSchemaErrorSeverity.Error, m_sourceLocation, columnMappingLineInfo.LineNumber, columnMappingLineInfo.LinePosition); m_parsingErrors.Add(error); errorFound = true; } } } // Make sure that propertyMappings is in the order of properties of the structuredType. // The rest of the code depends on it. Debug.Assert( errorFound || TypeHelpers.GetAllStructuralMembers(structuralType).Count == propertyMappings.Count && TypeHelpers.GetAllStructuralMembers(structuralType).Cast<EdmMember>().Zip(propertyMappings) .All(ppm => ppm.Key.EdmEquals(ppm.Value.Property)), "propertyMappings order does not correspond to the order of properties in the structuredType."); return !errorFound; }
public void VisitRowType_visits_child_properties() { var visitorMock = new Mock<EdmModelVisitor> { CallBase = true }; var rowType = new RowType(new[] { new EdmProperty("test"), }); visitorMock.Object.VisitRowType(rowType); visitorMock.Verify(v => v.VisitEdmProperty(rowType.DeclaredProperties.Single()), Times.Once()); }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { var lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression newRow; if (lambdaExpression != null) { // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions // created by users, because user-created expressions cannot be used for querying in O-space. // If that were to change, pushing span beyond a LambdaExpression could cause variable name // collisions between the variable names used in the Lambda and the names generated by the // RelationshipNavigationVisitor. newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression; } else { newRow = expression as DbNewInstanceExpression; } Dictionary<int, DbExpression> unmodifiedColumns = null; Dictionary<int, DbExpression> spannedColumns = null; for (var idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column var columnProp = rowType.Properties[idx]; // Construct an expression that defines the current column. DbExpression columnExpr = null; if (newRow != null) { // For a row-constructing NewInstance expression, the corresponding argument can simply be used columnExpr = newRow.Arguments[idx]; } else { // For all other expressions the property corresponding to the column name must be retrieved // from the row-typed expression columnExpr = expression.Property(columnProp.Name); } var spannedColumn = Rewrite(columnExpr); if (!ReferenceEquals(spannedColumn, columnExpr)) { // If so, then update the dictionary of column index to span information if (null == spannedColumns) { spannedColumns = new Dictionary<int, DbExpression>(); } spannedColumns[idx] = spannedColumn; } else { // Otherwise, update the dictionary of column index to unmodified expression if (null == unmodifiedColumns) { unmodifiedColumns = new Dictionary<int, DbExpression>(); } unmodifiedColumns[idx] = columnExpr; } } // A new expression need only be built if at least one column was spanned if (null == spannedColumns) { // No columns were spanned, indicate that the original expression should remain. return expression; } else { // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns. var columnArguments = new List<DbExpression>(rowType.Properties.Count); var properties = new List<EdmProperty>(rowType.Properties.Count); for (var idx = 0; idx < rowType.Properties.Count; idx++) { var columnProp = rowType.Properties[idx]; DbExpression columnDef = null; if (!spannedColumns.TryGetValue(idx, out columnDef)) { columnDef = unmodifiedColumns[idx]; } columnArguments.Add(columnDef); properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType)); } // Copy over any eLinq initializer metadata (if present, or null if not). // Note that this initializer metadata does not strictly match the new row type // that includes spanned columns, but will be correct once the object materializer // has interpreted the query results to produce the correct value for each colum. var rewrittenRow = new RowType(properties, rowType.InitializerMetadata); var rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow); DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments); // SQLBUDT #554182: If we insert a new projection we should should make sure to // not interfere with the nullability of the input. // In particular, if the input row is null and we construct a new row as a projection over its columns // we would get a row consisting of nulls, instead of a null row. // Thus, given an input X, we rewritte it as: if (X is null) then NULL else rewritten. if (newRow == null) { DbExpression condition = DbExpressionBuilder.CreateIsNullExpressionAllowingRowTypeArgument(expression); DbExpression nullExpression = rewrittenRowTypeUsage.Null(); rewritten = DbExpressionBuilder.Case( new List<DbExpression>(new[] { condition }), new List<DbExpression>(new[] { nullExpression }), rewritten); } // Add an entry to the spanned row type => original row type map for the new row type. AddSpannedRowType(rewrittenRow, expression.ResultType); if (lambdaExpression != null && newRow != null) { rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments); } return rewritten; } }
private static DbNewInstanceExpression CreateNewRowExpression( List<KeyValuePair<string, DbExpression>> columns, InitializerMetadata initializerMetadata) { var propertyValues = new List<DbExpression>(columns.Count); var properties = new List<EdmProperty>(columns.Count); for (var i = 0; i < columns.Count; i++) { var column = columns[i]; propertyValues.Add(column.Value); properties.Add(new EdmProperty(column.Key, column.Value.ResultType)); } var rowType = new RowType(properties, initializerMetadata); var typeUsage = TypeUsage.Create(rowType); return typeUsage.New(propertyValues); }
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> // Creates a record constructor // </summary> // <param name="type"> Type metadata that specifies that record type to construct </param> // <returns> A new NewRecordOp with the specified result type </returns> internal virtual NewRecordOp CreateNewRecordOp(RowType type) { return new NewRecordOp(TypeUsage.Create(type)); }
/// <summary> /// The factory method for constructing the <see cref="RowType" /> object. /// </summary> /// <param name="properties">Properties of the row type object.</param> /// <param name="metadataProperties">Metadata properties that will be added to the function. Can be null.</param> /// <returns> /// A new, read-only instance of the <see cref="RowType" /> object. /// </returns> public static RowType Create(IEnumerable<EdmProperty> properties, IEnumerable<MetadataProperty> metadataProperties) { Check.NotNull(properties, "properties"); var rowType = new RowType(properties); if (metadataProperties != null) { rowType.AddMetadataProperties(metadataProperties.ToList()); } rowType.SetReadOnly(); return rowType; }
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()); }
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; }
internal virtual CollectionColumnMap CreateColumnMapFromReaderAndClrType( DbDataReader reader, Type type, MetadataWorkspace workspace) { DebugCheck.NotNull(reader); DebugCheck.NotNull(type); DebugCheck.NotNull(workspace); // we require a default constructor var constructor = type.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); if (type.IsAbstract || (null == constructor && !type.IsValueType)) { throw new InvalidOperationException(Strings.ObjectContext_InvalidTypeForStoreQuery(type)); } // build a LINQ expression used by result assembly to create results var memberInfo = new List<Tuple<MemberAssignment, int, EdmProperty>>(); foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Select(p => p.GetPropertyInfoForSet())) { // for enums unwrap the type if nullable var propertyUnderlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; var propType = propertyUnderlyingType.IsEnum ? propertyUnderlyingType.GetEnumUnderlyingType() : prop.PropertyType; EdmType modelType; int ordinal; if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && workspace.TryDetermineCSpaceModelType(propType, out modelType) && (Helper.IsScalarType(modelType)) && prop.CanWriteExtended() && prop.GetIndexParameters().Length == 0 && null != prop.GetSetMethod(nonPublic: true)) { memberInfo.Add( Tuple.Create( Expression.Bind(prop, Expression.Parameter(prop.PropertyType, "placeholder")), ordinal, new EdmProperty(prop.Name, TypeUsage.Create(modelType)))); } } // initialize members in the order in which they appear in the reader var members = new MemberInfo[memberInfo.Count]; var memberBindings = new MemberBinding[memberInfo.Count]; var propertyMaps = new ColumnMap[memberInfo.Count]; var modelProperties = new EdmProperty[memberInfo.Count]; var i = 0; foreach (var memberGroup in memberInfo.GroupBy(tuple => tuple.Item2).OrderBy(tuple => tuple.Key)) { // make sure that a single column isn't contributing to multiple properties if (memberGroup.Count() != 1) { throw new InvalidOperationException( Strings.ObjectContext_TwoPropertiesMappedToSameColumn( reader.GetName(memberGroup.Key), String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray()))); } var member = memberGroup.Single(); var assignment = member.Item1; var ordinal = member.Item2; var modelProp = member.Item3; members[i] = assignment.Member; memberBindings[i] = assignment; propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal); modelProperties[i] = modelProp; i++; } var newExpr = null == constructor ? Expression.New(type) : Expression.New(constructor); var init = Expression.MemberInit(newExpr, memberBindings); var initMetadata = InitializerMetadata.CreateProjectionInitializer( (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init); // column map (a collection of rows with InitializerMetadata markup) var rowType = new RowType(modelProperties, initMetadata); var rowMap = new RecordColumnMap( TypeUsage.Create(rowType), "DefaultTypeProjection", propertyMaps, null); CollectionColumnMap collectionMap = new SimpleCollectionColumnMap( rowType.GetCollectionType().TypeUsage, rowType.Name, rowMap, null, null); return collectionMap; }
public void TranslateColumnMap_returns_correct_columntypes_and_nullablecolumns_for_anonymous_types() { var metadataWorkspaceMock = new Mock<MetadataWorkspace>(); metadataWorkspaceMock.Setup(m => m.GetQueryCacheManager()).Returns(QueryCacheManager.Create()); var edmProperties = new [] { new EdmProperty("P1Int", TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), new FacetValues { Nullable = false })), new EdmProperty("P2Bool", TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Boolean))) }; var cSpaceEntityType = new RowType(edmProperties); var entityTypeUsage = TypeUsage.Create(cSpaceEntityType); var recordMap = new RecordColumnMap( entityTypeUsage, "E", new[] { new ScalarColumnMap(cSpaceEntityType.Properties[0].TypeUsage, cSpaceEntityType.Properties[0].Name, 0, 0) }, new ScalarColumnMap(cSpaceEntityType.Properties[1].TypeUsage, cSpaceEntityType.Properties[1].Name, 0, 1)); var collectionMap = new SimpleCollectionColumnMap( entityTypeUsage, "MockCollectionType", recordMap, null, null); var factory = new Translator().TranslateColumnMap<object>( collectionMap, metadataWorkspaceMock.Object, new SpanIndex(), MergeOption.NoTracking, streaming: false, valueLayer: false); Assert.NotNull(factory); Assert.Equal(new[] { typeof(int), null }, factory.ColumnTypes); Assert.Equal(new[] { true, true }, factory.NullableColumns); }
private static bool IsPromotableTo(RowType fromRowType, RowType toRowType) { DebugCheck.NotNull(fromRowType); DebugCheck.NotNull(toRowType); if (fromRowType.Properties.Count != toRowType.Properties.Count) { return false; } for (var i = 0; i < fromRowType.Properties.Count; i++) { if (!IsPromotableTo(fromRowType.Properties[i].TypeUsage, toRowType.Properties[i].TypeUsage)) { return false; } } return true; }
/// <summary> /// Create a new VarInfo for a structured type Var where the newVars cannot include a null sentinel /// </summary> /// <param name="v"> The structured type Var </param> /// <param name="newType"> "Mapped" type for v </param> /// <param name="newVars"> List of vars corresponding to v </param> /// <param name="newProperties"> Flattened Properties </param> internal VarInfo CreateStructuredVarInfo(Var v, RowType newType, List<Var> newVars, List<EdmProperty> newProperties) { return CreateStructuredVarInfo(v, newType, newVars, newProperties, false); }
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()); }
/// <summary> /// Returns a Model type usage for a provider type /// </summary> /// <returns> model (CSpace) type usage </returns> internal TypeUsage GetModelTypeUsage() { if (_modelTypeUsage == null) { var edmType = EdmType; // If the edm type is already a cspace type, return the same type if (edmType.DataSpace == DataSpace.CSpace || edmType.DataSpace == DataSpace.OSpace) { return(this); } TypeUsage result; if (Helper.IsRowType(edmType)) { var sspaceRowType = (RowType)edmType; var properties = new EdmProperty[sspaceRowType.Properties.Count]; for (var i = 0; i < properties.Length; i++) { var sspaceProperty = sspaceRowType.Properties[i]; var newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage(); properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage); } var edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata); result = Create(edmRowType, Facets); } else if (Helper.IsCollectionType(edmType)) { var sspaceCollectionType = ((CollectionType)edmType); var newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage(); result = Create(new CollectionType(newTypeUsage), Facets); } else if (Helper.IsRefType(edmType)) { Debug.Assert(((RefType)edmType).ElementType.DataSpace == DataSpace.CSpace); result = this; } else if (Helper.IsPrimitiveType(edmType)) { result = ((PrimitiveType)edmType).ProviderManifest.GetEdmType(this); if (result == null) { throw new ProviderIncompatibleException(Strings.Mapping_ProviderReturnsNullType(ToString())); } if (!TypeSemantics.IsNullable(this)) { result = Create( result.EdmType, OverrideFacetValues( result.Facets, new FacetValues { Nullable = false })); } } else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType)) { result = this; } else { Debug.Assert(false, "Unexpected type found in entity data reader"); return(null); } Interlocked.CompareExchange(ref _modelTypeUsage, result, null); } return(_modelTypeUsage); }
/// <summary>Convert CSpace TypeMetadata into OSpace TypeMetadata</summary> /// <param name="clrType"></param> /// <returns>OSpace type metadata</returns> private EdmType ConvertOSpaceToCSpaceType(EdmType clrType) { EdmType cdmType = null; if (Helper.IsCollectionType(clrType)) { var elemType = ConvertOSpaceToCSpaceType(((CollectionType)clrType).TypeUsage.EdmType); cdmType = new CollectionType(elemType); } else if (Helper.IsRowType(clrType)) { var cdmProperties = new List<EdmProperty>(); var rowType = (RowType)clrType; foreach (var column in rowType.Properties) { var cdmPropertyType = ConvertOSpaceToCSpaceType(column.TypeUsage.EdmType); var cdmPorperty = new EdmProperty(column.Name, TypeUsage.Create(cdmPropertyType)); cdmProperties.Add(cdmPorperty); } cdmType = new RowType(cdmProperties, rowType.InitializerMetadata); } else if (Helper.IsRefType(clrType)) { cdmType = new RefType((EntityType)(ConvertOSpaceToCSpaceType(((RefType)clrType).ElementType))); } else { cdmType = ((ObjectTypeMapping)GetMap(clrType)).EdmType; } Debug.Assert((null != cdmType), "null converted clr type"); return cdmType; }
private static bool TryGetCommonType(RowType rowType1, RowType rowType2, out EdmType commonRowType) { if (rowType1.Properties.Count != rowType2.Properties.Count || rowType1.InitializerMetadata != rowType2.InitializerMetadata) { commonRowType = null; return false; } // find a common type for every property var commonProperties = new List<EdmProperty>(); for (var i = 0; i < rowType1.Properties.Count; i++) { TypeUsage columnCommonTypeUsage; if (!TryGetCommonType(rowType1.Properties[i].TypeUsage, rowType2.Properties[i].TypeUsage, out columnCommonTypeUsage)) { commonRowType = null; return false; } commonProperties.Add(new EdmProperty(rowType1.Properties[i].Name, columnCommonTypeUsage)); } commonRowType = new RowType(commonProperties, rowType1.InitializerMetadata); return true; }