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); }
internal virtual void Visit(RecordColumnMap columnMap, TArgType arg) { columnMap.NullSentinel?.Accept <TArgType>(this, arg); foreach (ColumnMap property in columnMap.Properties) { property.Accept <TArgType>(this, arg); } }
internal virtual void Visit(RecordColumnMap columnMap, TArgType arg) { ColumnMap nullSentinel = columnMap.NullSentinel; if (null != nullSentinel) { nullSentinel.Accept(this, arg); } foreach (var p in columnMap.Properties) { p.Accept(this, arg); } }
/// <summary> /// RecordColumnMap /// </summary> /// <param name="columnMap"></param> /// <param name="translationDelegate"></param> /// <returns></returns> internal override ColumnMap Visit(RecordColumnMap columnMap, ColumnMapTranslatorTranslationDelegate translationDelegate) { SimpleColumnMap newNullSentinel = columnMap.NullSentinel; if (null != newNullSentinel) { newNullSentinel = (SimpleColumnMap)translationDelegate(newNullSentinel); } VisitList(columnMap.Properties, translationDelegate); if (columnMap.NullSentinel != newNullSentinel) { columnMap = new RecordColumnMap(columnMap.Type, columnMap.Name, columnMap.Properties, newNullSentinel); } return(translationDelegate(columnMap)); }
/// <summary> /// Create a column map for a record type. Simply iterates through the /// list of fields, and produces a column map for each field /// </summary> /// <param name="typeInfo">Type information for the record type</param> /// <param name="name">column name</param> /// <returns></returns> private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name) { PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType"); SimpleColumnMap nullSentinelColumnMap = null; if (typeInfo.HasNullSentinelProperty) { nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName); } md.ReadOnlyMetadataCollection <md.EdmProperty> properties = TypeHelpers.GetProperties(typeInfo.Type); ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count]; for (int i = 0; i < propertyColumnMapList.Length; ++i) { md.EdmMember property = properties[i]; propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); } RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap); return(result); }
/// <summary> /// Create a column map for a record type. Simply iterates through the /// list of fields, and produces a column map for each field /// </summary> /// <param name="typeInfo">Type information for the record type</param> /// <param name="name">column name</param> /// <returns></returns> private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name) { PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType"); SimpleColumnMap nullSentinelColumnMap = null; if (typeInfo.HasNullSentinelProperty) { nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName); } md.ReadOnlyMetadataCollection<md.EdmProperty> properties = TypeHelpers.GetProperties(typeInfo.Type); ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count]; for (int i = 0; i < propertyColumnMapList.Length; ++i) { md.EdmMember property = properties[i]; propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); } RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap); return result; }
internal abstract TResultType Visit(RecordColumnMap columnMap, TArgType arg);
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); }
/// <summary> /// Build the collectionColumnMap from a store datareader, a type and an entitySet. /// </summary> /// <param name="storeDataReader"></param> /// <param name="edmType"></param> /// <param name="entitySet"></param> /// <returns></returns> internal static CollectionColumnMap CreateColumnMapFromReaderAndType(DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList) { Debug.Assert(Helper.IsEntityType(edmType) || null == entitySet, "The specified non-null EntitySet is incompatible with the EDM type specified."); // Next, build the ColumnMap directly from the edmType and entitySet provided. ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, edmType, renameList); ColumnMap elementColumnMap = null; // NOTE: We don't have a null sentinel here, because the stored proc won't // return one anyway; we'll just presume the data's always there. if (Helper.IsRowType(edmType)) { elementColumnMap = new RecordColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); } else if (Helper.IsComplexType(edmType)) { elementColumnMap = new ComplexTypeColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); } else if (Helper.IsScalarType(edmType)) { if (storeDataReader.FieldCount != 1) { throw EntityUtil.CommandExecutionDataReaderFieldCountForScalarType(); } elementColumnMap = new ScalarColumnMap(TypeUsage.Create(edmType), edmType.Name, 0, 0); } else if (Helper.IsEntityType(edmType)) { elementColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, edmType, entitySet, propertyColumnMaps, null/*renameList*/); } else { Debug.Assert(false, "unexpected edmType?"); } CollectionColumnMap collection = new SimpleCollectionColumnMap(edmType.GetCollectionType().TypeUsage, edmType.Name, elementColumnMap, null, null); return collection; }
/// <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 void Visit(RecordColumnMap columnMap, int dummy) { Append("R-", columnMap.Type); Append(",N", columnMap.NullSentinel); Append(",P", columnMap.Properties); }
internal override void Visit(RecordColumnMap columnMap, int dummy) { this.Append("R-", columnMap.Type); this.Append(",N", (ColumnMap)columnMap.NullSentinel); this.Append(",P", (IEnumerable <ColumnMap>)columnMap.Properties); }