/// <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; }
/// <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, md.RowType newType, List <Var> newVars, List <md.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 = null; return(false); } // find a common type for every property List <EdmProperty> commonProperties = new List <EdmProperty>(); for (int 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> /// Constructor /// </summary> /// <param name="newType">new "flat" record type corresponding to the Var's datatype</param> /// <param name="newVars">List of vars to replace current Var</param> /// <param name="newTypeProperties">List of properties in the "flat" record type</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> internal StructuredVarInfo(md.RowType newType, List <Var> newVars, List <md.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 = md.TypeUsage.Create(newType); }
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); }
private static bool IsPromotableTo(RowType fromRowType, RowType toRowType) { Debug.Assert(fromRowType != null && toRowType != null); if (fromRowType.Properties.Count != toRowType.Properties.Count) { return(false); } for (int i = 0; i < fromRowType.Properties.Count; i++) { if (!IsPromotableTo(fromRowType.Properties[i].TypeUsage, toRowType.Properties[i].TypeUsage)) { return(false); } } return(true); }
/// <summary> /// Determines if the given edmType is equal comparable. Consult "EntitySql Language Specification", /// section 7 - Comparison and Dependent Operations for details. /// </summary> /// <param name="edmType">an instance of an EdmType</param> /// <returns>true if edmType is equal-comparable, false otherwise</returns> private static bool IsEqualComparable(EdmType edmType) { if (Helper.IsPrimitiveType(edmType) || Helper.IsRefType(edmType) || Helper.IsEntityType(edmType) || Helper.IsEnumType(edmType)) { return(true); } else if (Helper.IsRowType(edmType)) { RowType rowType = (RowType)edmType; foreach (EdmProperty rowProperty in rowType.Properties) { if (!IsEqualComparable(rowProperty.TypeUsage)) { return(false); } } return(true); } return(false); }
/// <summary> /// EdmEquals override verifying the equivalence of all members and their type usages. /// </summary> /// <param name="item"></param> /// <returns></returns> internal override bool EdmEquals(MetadataItem item) { // short-circuit if this and other are reference equivalent if (Object.ReferenceEquals(this, item)) { return(true); } // check type of item if (null == item || BuiltInTypeKind.RowType != item.BuiltInTypeKind) { return(false); } RowType other = (RowType)item; // check each row type has the same number of members if (this.Members.Count != other.Members.Count) { return(false); } // verify all members are equivalent for (int ordinal = 0; ordinal < this.Members.Count; ordinal++) { EdmMember thisMember = this.Members[ordinal]; EdmMember otherMember = other.Members[ordinal]; // if members are different, return false if (!thisMember.EdmEquals(otherMember) || !thisMember.TypeUsage.EdmEquals(otherMember.TypeUsage)) { return(false); } } return(true); }
public void AddTvfReturnType(DbObjectKey key, RowType type) { _tvfReturnTypeLookup.Add(key, type); }
/// <summary> /// Determines the expected shape of store results. We expect a column for every property /// of the mapped type (or types) and a column for every discriminator column. We make no /// assumptions about the order of columns: the provider is expected to determine appropriate /// types by looking at the names of the result columns, not the order of columns, which is /// different from the typical handling of row types in the EF. /// </summary> /// <remarks> /// Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL /// function. /// </remarks> /// <returns>Row type.</returns> internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace, int resultSetIndex) { FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex); // Collect all columns as name-type pairs. Dictionary<string, TypeUsage> columns = new Dictionary<string, TypeUsage>(); // Figure out which entity types we expect to yield from the function. IEnumerable<StructuralType> structuralTypes; if (0 == resultMapping.NormalizedEntityTypeMappings.Count) { // No explicit type mappings; just use the type specified in the ReturnType attribute on the function. StructuralType structuralType; MetadataHelper.TryGetFunctionImportReturnType<StructuralType>(this.FunctionImport, resultSetIndex, out structuralType); Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); structuralTypes = new StructuralType[] { structuralType }; } else { // Types are explicitly mapped. structuralTypes = resultMapping.MappedEntityTypes.Cast<StructuralType>(); } // Gather columns corresponding to all properties. foreach (StructuralType structuralType in structuralTypes) { foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) { // NOTE: if a complex type is encountered, the column map generator will // throw. For now, we just let them through. // We expect to see each property multiple times, so we use indexer rather than // .Add. columns[property.Name] = property.TypeUsage; } } // Gather discriminator columns. foreach (string discriminatorColumn in this.GetDiscriminatorColumns(resultSetIndex)) { if (!columns.ContainsKey(discriminatorColumn)) { // TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false); columns.Add(discriminatorColumn, type); } } // Expected type is a collection of rows RowType rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); TypeUsage result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType))); return result; }
/// <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 NewRecordOp CreateNewRecordOp(RowType type) { return new NewRecordOp(TypeUsage.Create(type)); }
/// <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); }
private static bool IsPromotableTo(RowType fromRowType, RowType toRowType) { Debug.Assert(fromRowType != null && toRowType != null); if (fromRowType.Properties.Count != toRowType.Properties.Count) { return false; } for (int i = 0; i < fromRowType.Properties.Count; i++) { if (!IsPromotableTo(fromRowType.Properties[i].TypeUsage, toRowType.Properties[i].TypeUsage)) { return false; } } return true; }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression 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(int idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column EdmProperty 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); } DbExpression spannedColumn = this.Rewrite(columnExpr); if (!object.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. List<DbExpression> columnArguments = new List<DbExpression>(rowType.Properties.Count); List<EdmProperty> properties = new List<EdmProperty>(rowType.Properties.Count); for (int idx = 0; idx < rowType.Properties.Count; idx++) { EdmProperty 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. RowType rewrittenRow = new RowType(properties, rowType.InitializerMetadata); TypeUsage 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 = DbExpressionBuilder.Null(rewrittenRowTypeUsage); rewritten = DbExpressionBuilder.Case( new List<DbExpression>(new DbExpression[] { condition }), new List<DbExpression>(new DbExpression[] { 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 void AddSpannedRowType(RowType spannedType, TypeUsage originalType) { if (null == _spanIndex) { _spanIndex = new SpanIndex(); } _spanIndex.AddSpannedRowType(spannedType, originalType); }
private ComplexType CreateModelComplexTypeForTvfResult(LoadMethodSessionState session, string functionImportName, RowType tvfReturnType) { Debug.Assert(MetadataUtil.IsStoreType(tvfReturnType), "this is not a store type"); // create all the properties List<EdmMember> members = new List<EdmMember>(); UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false); string name = CreateModelName(functionImportName + "_Result", session.UsedGlobalModelTypeNames); // Don't want to have a property with the same name as the complex type usedPropertyNames.RegisterUsedIdentifier(name); foreach (EdmProperty storeProperty in tvfReturnType.Properties) { EdmProperty property = CreateModelProperty(session, storeProperty, usedPropertyNames); members.Add(property); } var complexType = new ComplexType(name, _namespaceName, DataSpace.CSpace); foreach (var m in members) { complexType.AddMember(m); } return complexType; }
private DbNewInstanceExpression CreateNewRowExpression(List<KeyValuePair<string, DbExpression>> columns, InitializerMetadata initializerMetadata) { List<DbExpression> propertyValues = new List<DbExpression>(columns.Count); List<EdmProperty> properties = new List<EdmProperty>(columns.Count); for (int i = 0; i < columns.Count; i++) { var column = columns[i]; propertyValues.Add(column.Value); properties.Add(new EdmProperty(column.Key, column.Value.ResultType)); } RowType rowType = new RowType(properties, initializerMetadata); TypeUsage typeUsage = TypeUsage.Create(rowType); return typeUsage.New(propertyValues); }
/// <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; }
// Generates and caches a command definition for the given function internal DbCommandDefinition GenerateCommandDefinition(StorageModificationFunctionMapping functionMapping) { if (null == m_modificationFunctionCommandDefinitions) { m_modificationFunctionCommandDefinitions = new Dictionary<StorageModificationFunctionMapping,DbCommandDefinition>(); } DbCommandDefinition commandDefinition; if (!m_modificationFunctionCommandDefinitions.TryGetValue(functionMapping, out commandDefinition)) { // synthesize a RowType for this mapping TypeUsage resultType = null; if (null != functionMapping.ResultBindings && 0 < functionMapping.ResultBindings.Count) { List<EdmProperty> properties = new List<EdmProperty>(functionMapping.ResultBindings.Count); foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings) { properties.Add(new EdmProperty(resultBinding.ColumnName, resultBinding.Property.TypeUsage)); } RowType rowType = new RowType(properties); CollectionType collectionType = new CollectionType(rowType); resultType = TypeUsage.Create(collectionType); } // add function parameters IEnumerable<KeyValuePair<string, TypeUsage>> functionParams = functionMapping.Function.Parameters.Select(paramInfo => new KeyValuePair<string, TypeUsage>(paramInfo.Name, paramInfo.TypeUsage)); // construct DbFunctionCommandTree including implict return type DbFunctionCommandTree tree = new DbFunctionCommandTree(m_metadataWorkspace, DataSpace.SSpace, functionMapping.Function, resultType, functionParams); commandDefinition = m_providerServices.CreateCommandDefinition(tree); } return commandDefinition; }
/// <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)) { EdmType elemType = ConvertOSpaceToCSpaceType(((CollectionType)clrType).TypeUsage.EdmType); cdmType = new CollectionType(elemType); } else if (Helper.IsRowType(clrType)) { List<EdmProperty> cdmProperties = new List<EdmProperty>(); foreach (EdmProperty column in ((RowType)clrType).Properties) { EdmType cdmPropertyType = ConvertOSpaceToCSpaceType(column.TypeUsage.EdmType); EdmProperty cdmPorperty = new EdmProperty(column.Name, TypeUsage.Create(cdmPropertyType)); cdmProperties.Add(cdmPorperty); } cdmType = new RowType(cdmProperties, ((RowType)clrType).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; }
/// <summary>Convert CSpace TypeMetadata into OSpace TypeMetadata</summary> /// <param name="cdmType"></param> /// <returns>OSpace type metadata</returns> private EdmType ConvertCSpaceToOSpaceType(EdmType cdmType) { EdmType clrType = null; if (Helper.IsCollectionType(cdmType)) { var elemType = ConvertCSpaceToOSpaceType(((CollectionType)cdmType).TypeUsage.EdmType); clrType = new CollectionType(elemType); } else if (Helper.IsRowType(cdmType)) { var clrProperties = new List<EdmProperty>(); var rowType = (RowType)cdmType; foreach (var column in rowType.Properties) { var clrPropertyType = ConvertCSpaceToOSpaceType(column.TypeUsage.EdmType); var clrProperty = new EdmProperty(column.Name, TypeUsage.Create(clrPropertyType)); clrProperties.Add(clrProperty); } clrType = new RowType(clrProperties, rowType.InitializerMetadata); } else if (Helper.IsRefType(cdmType)) { clrType = new RefType((EntityType)ConvertCSpaceToOSpaceType(((RefType)cdmType).ElementType)); } else if (Helper.IsPrimitiveType(cdmType)) { clrType = m_objectCollection.GetMappedPrimitiveType(((PrimitiveType)cdmType).PrimitiveTypeKind); } else { clrType = ((ObjectTypeMapping)GetMap(cdmType)).ClrType; } Debug.Assert((null != clrType), "null converted clr type"); return clrType; }
private void CreateTvfReturnRowType( LoadMethodSessionState session, IList<TableDetailsRow> columns, ICollection<string> primaryKeys, DbObjectType objectType, List<EdmSchemaError> errors) { Debug.Assert(columns.Count != 0, "Trying to create a RowType with 0 properties"); Debug.Assert(primaryKeys != null, "primaryKeys != null"); DbObjectKey tableKey = columns[0].CreateDbObjectKey(objectType); if (errors == null) { errors = new List<EdmSchemaError>(); } IList<string> excludedColumns; var properties = CreateEdmProperties(session, columns, tableKey, errors, out excludedColumns); var rowType = new RowType(properties); rowType.SetReadOnly(); session.AddTvfReturnType(tableKey, rowType); if (rowType.Properties.Count == 0) { session.InvalidTypes.Add(rowType); } session.AddErrorsForType(rowType, errors); }
/// <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, md.RowType newType, List <Var> newVars, List <md.EdmProperty> newProperties) { return(CreateStructuredVarInfo(v, newType, newVars, newProperties, false)); }
private static bool CompareTypes(TypeUsage fromType, TypeUsage toType, bool equivalenceOnly) { Debug.Assert(fromType != null && toType != null); // If the type usages are the same reference, they are equal. if (object.ReferenceEquals(fromType, toType)) { return(true); } if (fromType.EdmType.BuiltInTypeKind != toType.EdmType.BuiltInTypeKind) { return(false); } // // Ensure structural evaluation for Collection, Ref and Row types // if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType) { // Collection Type: Just compare the Element types return(CompareTypes(((CollectionType)fromType.EdmType).TypeUsage, ((CollectionType)toType.EdmType).TypeUsage, equivalenceOnly)); } else if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType) { // Both are Reference Types, so compare the referenced Entity types return(((RefType)fromType.EdmType).ElementType.EdmEquals(((RefType)toType.EdmType).ElementType)); } else if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType) { // Row Types RowType fromRow = (RowType)fromType.EdmType; RowType toRow = (RowType)toType.EdmType; // Both are RowTypes, so compare the structure. // The number of properties must be the same. if (fromRow.Properties.Count != toRow.Properties.Count) { return(false); } // Compare properties. For an equivalence comparison, only // property types must match, otherwise names and types must match. for (int idx = 0; idx < fromRow.Properties.Count; idx++) { EdmProperty fromProp = fromRow.Properties[idx]; EdmProperty toProp = toRow.Properties[idx]; if (!equivalenceOnly && (fromProp.Name != toProp.Name)) { return(false); } if (!CompareTypes(fromProp.TypeUsage, toProp.TypeUsage, equivalenceOnly)) { return(false); } } return(true); } // // compare non-transient type usages - simply compare the edm types instead // return(fromType.EdmType.EdmEquals(toType.EdmType)); }
/// <summary> /// Returns a Model type usage for a provider type /// </summary> /// <returns>model (CSpace) type usage</returns> internal TypeUsage GetModelTypeUsage() { if (_modelTypeUsage == null) { EdmType edmType = this.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)) { RowType sspaceRowType = (RowType)edmType; EdmProperty[] properties = new EdmProperty[sspaceRowType.Properties.Count]; for (int i = 0; i < properties.Length; i++) { EdmProperty sspaceProperty = sspaceRowType.Properties[i]; TypeUsage newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage(); properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage); } RowType edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata); result = TypeUsage.Create(edmRowType, this.Facets); } else if (Helper.IsCollectionType(edmType)) { CollectionType sspaceCollectionType = ((CollectionType)edmType); TypeUsage newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage(); result = TypeUsage.Create(new CollectionType(newTypeUsage), this.Facets); } else if (Helper.IsRefType(edmType)) { System.Diagnostics.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 EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Mapping_ProviderReturnsNullType(this.ToString())); } if (!TypeSemantics.IsNullable(this)) { result = TypeUsage.Create(result.EdmType, OverrideFacetValues(result.Facets, new FacetValues { Nullable = false })); } } else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType)) { result = this; } else { System.Diagnostics.Debug.Assert(false, "Unexpected type found in entity data reader"); return(null); } System.Threading.Interlocked.CompareExchange(ref _modelTypeUsage, result, null); } return(_modelTypeUsage); }
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(); } }
private void AddSpanMap(RowType rowType, Dictionary<int, AssociationEndMember> columnMap) { if (null == _spanIndex) { _spanIndex = new SpanIndex(); } _spanIndex.AddSpanMap(rowType, columnMap); }
/// <summary> /// Requires: a public type with a public, default constructor. Returns a column map initializing the type /// and all properties of the type with a public setter taking a primitive type and having a corresponding /// column in the reader. /// </summary> internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(DbDataReader reader, Type type, MetadataWorkspace workspace) { Debug.Assert(null != reader); Debug.Assert(null != type); Debug.Assert(null != workspace); // we require a default constructor ConstructorInfo constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); if (type.IsAbstract || (null == constructor && !type.IsValueType)) { throw EntityUtil.InvalidOperation( Strings.ObjectContext_InvalidTypeForStoreQuery(type)); } // build a LINQ expression used by result assembly to create results var memberInfo = new List<Tuple<MemberAssignment, int, EdmProperty>>(); foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { // for enums unwrap the type if nullable var propertyUnderlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; Type propType = propertyUnderlyingType.IsEnum ? propertyUnderlyingType.GetEnumUnderlyingType() : prop.PropertyType; EdmType modelType; int ordinal; if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && MetadataHelper.TryDetermineCSpaceModelType(propType, workspace, out modelType) && (Helper.IsScalarType(modelType)) && prop.CanWrite && 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 MemberInfo[] members = new MemberInfo[memberInfo.Count]; MemberBinding[] memberBindings = new MemberBinding[memberInfo.Count]; ColumnMap[] propertyMaps = new ColumnMap[memberInfo.Count]; EdmProperty[] modelProperties = new EdmProperty[memberInfo.Count]; int 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 EntityUtil.InvalidOperation(Strings.ObjectContext_TwoPropertiesMappedToSameColumn( reader.GetName(memberGroup.Key), String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray()))); } var member = memberGroup.Single(); MemberAssignment assignment = member.Item1; int ordinal = member.Item2; EdmProperty modelProp = member.Item3; members[i] = assignment.Member; memberBindings[i] = assignment; propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal); modelProperties[i] = modelProp; i++; } NewExpression newExpr = null == constructor ? Expression.New(type) : Expression.New(constructor); MemberInitExpression init = Expression.MemberInit(newExpr, memberBindings); InitializerMetadata initMetadata = InitializerMetadata.CreateProjectionInitializer( (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init, members); // column map (a collection of rows with InitializerMetadata markup) RowType rowType = new RowType(modelProperties, initMetadata); RecordColumnMap rowMap = new RecordColumnMap(TypeUsage.Create(rowType), "DefaultTypeProjection", propertyMaps, null); CollectionColumnMap collectionMap = new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage, rowType.Name, rowMap, null, null); return collectionMap; }
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); } RowType 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(this.OtherContent); _typeUsage = TypeUsage.Create(rowType); } return _typeUsage; }
/// <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 TableMD CreateFlatTableDefinition(RowType type) { return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null); }
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 List<EdmProperty> commonProperties = new List<EdmProperty>(); for (int 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; }
public bool TryGetTvfReturnType(DbObjectKey key, out RowType type) { return _tvfReturnTypeLookup.TryGetValue(key, out type); }