예제 #1
0
 /// <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;
 }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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);
        }
예제 #4
0
 /// <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);
 }
예제 #6
0
        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);
        }
예제 #7
0
 /// <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);
 }
예제 #8
0
        /// <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;
        }
예제 #11
0
 /// <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));
 }
예제 #12
0
 /// <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);
 }
예제 #13
0
        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;
        }
예제 #14
0
        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;
            }
        }
예제 #15
0
        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;
        }
예제 #17
0
 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);
        }
예제 #23
0
 /// <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));
 }
예제 #24
0
        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));
        }
예제 #25
0
        /// <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);
        }
예제 #26
0
 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();
     }
 }
예제 #27
0
        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;
        }
예제 #29
0
        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;
        }
예제 #30
0
 /// <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);
 }
예제 #31
0
        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);
 }