internal abstract TResultType Visit(SimplePolymorphicColumnMap columnMap, TArgType arg);
/// <summary> /// Creates a column map for a polymorphic type. This method first /// creates column maps for each type that is a subtype of the input type, /// and then creates a dictionary of typeid value -> column /// Finally, a PolymorphicColumnMap is created with these pieces of information /// </summary> /// <param name="typeInfo">Info about the type</param> /// <param name="name">column name</param> /// <returns></returns> private SimplePolymorphicColumnMap CreatePolymorphicColumnMap(TypeInfo typeInfo, string name) { // if the typeInfo has a DiscriminatorMap, use TrailingSpaceComparer to ensure that lookups // against discriminator values that SQL Server has right-padded (e.g. nchar and char) are properly // interpreted Dictionary<object, TypedColumnMap> discriminatorMap = new Dictionary<object, TypedColumnMap>( typeInfo.RootType.DiscriminatorMap == null ? null : TrailingSpaceComparer.Instance); // abstract types may not have discriminator values, but may nonetheless be interesting List<TypedColumnMap> allMaps = new List<TypedColumnMap>(); // SQLBUDT #433011 -- Polymorphic types must construct column maps // that map to the entire type hierarchy, so we // need to use the RootType, not the current type. TypeInfo rootTypeInfo = typeInfo.RootType; // Get the type discriminant column first SimpleColumnMap typeIdColumnMap = CreateTypeIdColumnMap(rootTypeInfo.TypeIdProperty); // Prepare a place for the constructors to put the columns on the base // type, as they identify them. TypedColumnMap rootTypeColumnMap = null; // process complex/entity types appropriately // use the same name for the column if (md.TypeSemantics.IsComplexType(typeInfo.Type)) { rootTypeColumnMap = CreateComplexTypeColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps); } else { rootTypeColumnMap = CreateEntityColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps, true); } // Naturally, nothing is simple; we need to walk the rootTypeColumnMap hierarchy // and find the column map for the type that we are supposed to have as the base // type of this hierarchy. TypedColumnMap baseTypeColumnMap = null; foreach (TypedColumnMap value in allMaps) { if (md.TypeSemantics.IsStructurallyEqual(value.Type, typeInfo.Type)) { baseTypeColumnMap = value; break; } } PlanCompiler.Assert(null != baseTypeColumnMap, "Didn't find requested type in polymorphic type hierarchy?"); // Create a polymorphic column map SimplePolymorphicColumnMap result = new SimplePolymorphicColumnMap(typeInfo.Type, name, baseTypeColumnMap.Properties, typeIdColumnMap, discriminatorMap); return result; }
public void TranslateColumnMap_returns_correct_columntypes_and_nullablecolumns_for_discriminated_types() { var metadataWorkspaceMock = new Mock<MetadataWorkspace>(); metadataWorkspaceMock.Setup(m => m.GetQueryCacheManager()).Returns(QueryCacheManager.Create()); var typeChoices = new Dictionary<object, TypedColumnMap>(); var entityColumnMap = (EntityColumnMap)BuildSimpleEntitySetColumnMap(metadataWorkspaceMock).Element; typeChoices.Add(true, entityColumnMap); var recordMap = new SimplePolymorphicColumnMap( entityColumnMap.Type, "E", new ColumnMap[0], new ScalarColumnMap(TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Boolean)), "discriminator", 0, 2), typeChoices); var collectionMap = new SimpleCollectionColumnMap( entityColumnMap.Type, "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), typeof(int), typeof(bool) }, factory.ColumnTypes); Assert.Equal(new[] { true, true, true }, factory.NullableColumns); }