Share via


Type Mapping

Type mapping is the process through which data object types defined by data providers are mapped to generic data types defined by the Visual Studio metadata engine.

The problem of mapping data-source-specific to generic concepts (the "b:g mapping problem") occurs when you have object types that are kinds of other types, as, for example, when a unique key is a kind of constraint, or a primary key is a kind of unique key. Therefore, a data-source-specific type might be either generalized (for example, a Constraint) or granular (like a PrimaryKey, UniqueKey, or ForeignKey). If the generic concepts are not equivalently generalized or granular, you encounter the b-g mapping problem.

Type mapping occurs in four flavors:

  • 1:1 Type Mapping

  • 1:g Type Mapping

  • b:1 Type Mapping

  • b:g Type Mapping

The following sections address each of the cases in turn.

1:1 Type Mapping

A one-to-one mapping is the simplest case and occurs when a data provider has a single data-source-specific type that maps to just one generic mapped type. You can apply a one-to-one mapping such as this by specifying the underlyingType attribute in the MappedType element, which maps the generic mapped type (MappedType XML element) to the data-source-specific type (Type XML element). This is illustrated in the following example of XML:

The following XML from the DataObjectSupport XML file shows the data-source-specific Column declaration:

<Type name="Column" preferredOrdering="Database, Schema, Table, Id">
    <IdentifierRef name="SubSchemaObjectTypeIdentifier" arguments="Table" />
    <Properties>
        <PropertyListRef name="ColumnProperties" />
        <Property name="Computed" type="System.Boolean" />
    </Properties>
    <Services>
        <ServiceRef name="SubSchemaObjectTypeObjectSelectorService" arguments="Table, Table, Column, ColumnSelectorMappings" />
        <ServiceRef name="SubSchemaObjectTypeDSRefBuilderService" arguments="Table, 101, Field, 102" />
    </Services>
</Type>

The following XML from the DataObjectSupport XML file shows the declaration of the TableColumn generic mapped type that is mapped to the above Column type through the underlyingType attribute:

<MappedType name="TableColumn" underlyingType="Column">
    <Selection restrictions="{Catalog},{Schema},{Table},{Name}" />
    <IdentifierRef name="MappedSubTypeIdentifier" arguments="Table" />
    <Properties>
        <Property name="Name" isIdentifierPart="true" />
        <Property name="Ordinal" underlyingMember="Id" />
        <PropertyListRef name="MappedSubTypeDataTypeProperties" />
        <Property name="IsNullable" underlyingMember="Nullable" />
        <Property name="IsComputed" underlyingMember="Computed" />
    </Properties>
</MappedType>

To extend the example, consider the architecture of unique constraints in SQL Server. For every unique constraint there is always an index, and all metadata for exposing unique constraints is provided by way of its index. One can say, then, that a unique key is a kind of index in SQL Server. In cases where a generic concept, Index, supports the idea that it might also be a unique key, the mapping is 1:1 and is handled easily.

1:g Type Mapping

The case of mapping a data-source-specific type to a generic mapped type is somewhat more complicated. To illustrate, consider the above example (for the 1:1 mapping, that is). In this case, however, the generic mapped type is UniqueKey; this results in a 1:g mapping, wherein a single data-source-specific type (Index) represents more than one generic mapped type (both UniqueKey and Index). A data provider now needs to map multiple mapped types to an object type, as in the following:

<MappedType name="TableUniqueKey" underlyingType="Index">
    <Selection restrictions="{Catalog},{Schema},{Table},{Name}" filter="KeyType > 0" />
    <IdentifierRef name="MappedSubTypeIdentifier" arguments="Table" />
    <Properties>
        <Property name="Name" isIdentifierPart="true" />
        <Property name="IsPrimary" underlyingMember="KeyType">
            <Conversion>
                <Calculate expr="IIF({0} = 1, true, false)" exprType="System.Boolean" />
            </Conversion>
        </Property>
    </Properties>
</MappedType>
<MappedType name="Index" underlyingType="Index">
    <Selection restrictions="{Catalog},{Schema},{Table},{Name}" />
</MappedType>

Notice the filter attribute specified on the UniqueKey concept. This is the best way to identify the subset of instances of the data-source-specific type that actually represents this generic concept.

b:1 Type Mapping

The case of a data provider mapping multiple data-source-specific types to a single generic mapped type requires specifying a single mapped type on multiple underlying types. For example, assume that the data provider defines data-source-specific types UniqueKey and ForeignKey, which are kinds of constraints. Then, suppose there is a generic mapped type, Constraint, which encompasses all constraint types. The result is a b:1 mapping—that is, multiple data-source-specific types represented by a single generic mapped type.

Enabling this case requires a bit more XML than did previous cases, as in the following example:

<Type name="ForeignKey" preferredOrdering="Database, Schema, Table, Name">
…
</Type>
<Type name="UniqueKey" preferredOrdering="Database, Schema, Table, Name">
…
</Type>
<MappedType name="Constraint" underlyingType="ForeignKey">
…
</MappedType>
<MappedType name="Constraint" underlyingType="UniqueKey">
…
</MappedType>

b:g Type Mapping

Finally, the case of mapping multiple data-source-specific types to multiple generic concepts is effectively a combination of the 1:g and b:1 mappings. For example, suppose that a data-source-specific data provider separates the concepts of a primary key from other constraints (for example, from unique key and foreign key). In this case there could be data-source-specific types PrimaryKey and Constraint. Now, suppose there are generic concepts UniqueKey and ForeignKey, where the UniqueKey concept encompasses both primary and unique keys. This is a b:g mapping, in which multiple data-source-specific types are represented by multiple generic mapped types.

To handle this case, the data provider applies this mapping by specifying multiple mapped types on multiple data-source-specific types, as illustrated in the following XML:

<Type name="PrimaryKey" preferredOrdering="Database, Schema, Table, Name">
…
</Type>
<Type name="Constraint" preferredOrdering="Database, Schema, Table, Name">
…
</Type>
<MappedType name="UniqueKey" underlyingType="PrimaryKey">
…
</MappedType>
<MappedType name="UniqueKey" underlyingType="Constraint">
    <Selection restrictions="{Catalog},{Schema},{Table},{Name}" filter="IsUnique = true" />
</MappedType>
<MappedType name="ForeignKey" underlyingType="Constraint">
    <Selection restrictions="{Catalog},{Schema},{Table},{Name}" filter="IsForeign = true" />
</MappedType>

See Also

Concepts

Identifier and Property Mapping

Mapping Object Type Identifiers and Properties to Generic Types