ADO EF - Errors Mapping Associations between Derived Types in TPH

Possible Workaround

  1. Create a separate column for each association between derived types and make each of these columns nullable
  2. Create a foreign key between each of these new columns and the primary key table.
  3. Map each association in your Entity Model to a specific, unique column and foreign key so that each column and foreign key is only used once.

Problems

This is quite an undesirable solution because it explodes out the number of columns you need.

  • More Columns - Adding a column for each association between derived types results in an explosion on the number of columns.
  • Empty Columns In the case of TPH, it means you'll have a lot of empty columns in your table.
  • SQL JOIN - Switching from TPH to TPT to avoid the number of empty columns results in the necessity for EF to use a JOIN which will have to occur extremely frequently (almost every time you deal with any of the derived types).
  • Refactoring If you add a derived type in the future, you not only have to update your Entity model (*.edmx) and the it's mapping but you will also have to change the database schema by adding additional columns!

Example

For the Link/Node example above, the resulting database schema would look like this:

GraphExample Workaround Database Schema


Code

SQL:

USE [GraphExample2]
GO
/****** Object:  Table [dbo].[Node]    Script Date: 02/26/2009 15:45:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Node](
    [NodeID] [int] IDENTITY(1,1) NOT NULL,
    [NodeTypeDiscriminator] [int] NOT NULL,
    [Name] [varchar](255) NOT NULL,
    [Description] [varchar](1023) NULL,
 CONSTRAINT [PK_Node] PRIMARY KEY CLUSTERED 
(
    [NodeID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[Link]    Script Date: 02/26/2009 15:45:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Link](
    [LinkID] [int] IDENTITY(1,1) NOT NULL,
    [LinkTypeDiscriminator] [int] NOT NULL,
    [LeaderID] [int] NULL,
    [FollowerID] [int] NULL,
    [PersonID] [int] NULL,
    [LocationID] [int] NULL,
    [Name] [varchar](255) NULL,
    [Description] [varchar](1023) NULL,
 CONSTRAINT [PK_Link] PRIMARY KEY CLUSTERED 
(
    [LinkID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object:  ForeignKey [FK_Link_Node_Follower]    Script Date: 02/26/2009 15:45:53 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Follower] FOREIGN KEY([FollowerID])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Follower]
GO
/****** Object:  ForeignKey [FK_Link_Node_Leader]    Script Date: 02/26/2009 15:45:53 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Leader] FOREIGN KEY([LeaderID])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Leader]
GO
/****** Object:  ForeignKey [FK_Link_Node_Location]    Script Date: 02/26/2009 15:45:53 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Location] FOREIGN KEY([LocationID])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Location]
GO
/****** Object:  ForeignKey [FK_Link_Node_Person]    Script Date: 02/26/2009 15:45:53 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Person] FOREIGN KEY([PersonID])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Person]
GO

EDMX:

<?xml version="1.0" encoding="utf-8"?>
  <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
    <!-- EF Runtime content -->
    <edmx:Runtime>
      <!-- SSDL content -->
      <edmx:StorageModels>
        <Schema Namespace="GraphModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">
          <EntityContainer Name="GraphModelStoreContainer">
            <EntitySet Name="Link" EntityType="GraphModel.Store.Link" store:Type="Tables" Schema="dbo" />
            <EntitySet Name="Node" EntityType="GraphModel.Store.Node" store:Type="Tables" Schema="dbo" />
            <AssociationSet Name="FK_Link_Node_Follower" Association="GraphModel.Store.FK_Link_Node_Follower">
              <End Role="Node" EntitySet="Node" />
              <End Role="Link" EntitySet="Link" />
            </AssociationSet>
            <AssociationSet Name="FK_Link_Node_Leader" Association="GraphModel.Store.FK_Link_Node_Leader">
              <End Role="Node" EntitySet="Node" />
              <End Role="Link" EntitySet="Link" />
            </AssociationSet>
            <AssociationSet Name="FK_Link_Node_Location" Association="GraphModel.Store.FK_Link_Node_Location">
              <End Role="Node" EntitySet="Node" />
              <End Role="Link" EntitySet="Link" />
            </AssociationSet>
            <AssociationSet Name="FK_Link_Node_Person" Association="GraphModel.Store.FK_Link_Node_Person">
              <End Role="Node" EntitySet="Node" />
              <End Role="Link" EntitySet="Link" />
            </AssociationSet>
          </EntityContainer>
          <EntityType Name="Link">
            <Key>
              <PropertyRef Name="LinkID" />
            </Key>
            <Property Name="LinkID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
            <Property Name="LinkTypeDiscriminator" Type="int" Nullable="false" />
            <Property Name="LeaderID" Type="int" />
            <Property Name="FollowerID" Type="int" />
            <Property Name="PersonID" Type="int" />
            <Property Name="LocationID" Type="int" />
            <Property Name="Name" Type="varchar" MaxLength="255" />
            <Property Name="Description" Type="varchar" MaxLength="1023" />
          </EntityType>
          <EntityType Name="Node">
            <Key>
              <PropertyRef Name="NodeID" />
            </Key>
            <Property Name="NodeID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
            <Property Name="NodeTypeDiscriminator" Type="int" Nullable="false" />
            <Property Name="Name" Type="varchar" Nullable="false" MaxLength="255" />
            <Property Name="Description" Type="varchar" MaxLength="1023" />
          </EntityType>
          <Association Name="FK_Link_Node_Follower">
            <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="0..1" />
            <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
            <ReferentialConstraint>
              <Principal Role="Node">
                <PropertyRef Name="NodeID" />
              </Principal>
              <Dependent Role="Link">
                <PropertyRef Name="FollowerID" />
              </Dependent>
            </ReferentialConstraint>
          </Association>
          <Association Name="FK_Link_Node_Leader">
            <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="0..1" />
            <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
            <ReferentialConstraint>
              <Principal Role="Node">
                <PropertyRef Name="NodeID" />
              </Principal>
              <Dependent Role="Link">
                <PropertyRef Name="LeaderID" />
              </Dependent>
            </ReferentialConstraint>
          </Association>
          <Association Name="FK_Link_Node_Location">
            <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="0..1" />
            <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
            <ReferentialConstraint>
              <Principal Role="Node">
                <PropertyRef Name="NodeID" />
              </Principal>
              <Dependent Role="Link">
                <PropertyRef Name="LocationID" />
              </Dependent>
            </ReferentialConstraint>
          </Association>
          <Association Name="FK_Link_Node_Person">
            <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="0..1" />
            <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
            <ReferentialConstraint>
              <Principal Role="Node">
                <PropertyRef Name="NodeID" />
              </Principal>
              <Dependent Role="Link">
                <PropertyRef Name="PersonID" />
              </Dependent>
            </ReferentialConstraint>
          </Association>
        </Schema>
      </edmx:StorageModels>
      <!-- CSDL content -->
      <edmx:ConceptualModels>
        <Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="GraphModel" Alias="Self">
          <EntityContainer Name="GraphModelContainer" >
            <EntitySet Name="NodeSet" EntityType="GraphModel.Node" />
            <EntitySet Name="LinkSet" EntityType="GraphModel.Link" />
            <AssociationSet Name="PersonPersonToPerson_Leader" Association="GraphModel.PersonPersonToPerson_Leader">
              <End Role="Person" EntitySet="NodeSet" />
              <End Role="PersonToPerson" EntitySet="LinkSet" />
            </AssociationSet>
            <AssociationSet Name="PersonPersonToPerson_Follower" Association="GraphModel.PersonPersonToPerson_Follower">
              <End Role="Person" EntitySet="NodeSet" />
              <End Role="PersonToPerson" EntitySet="LinkSet" />
            </AssociationSet>
            <AssociationSet Name="Person_PersonToLocation" Association="GraphModel.Person_PersonToLocation">
              <End Role="Person" EntitySet="NodeSet" />
              <End Role="PersonToLocation" EntitySet="LinkSet" />
            </AssociationSet>
            <AssociationSet Name="Location_PersonToLocation" Association="GraphModel.Location_PersonToLocation">
              <End Role="Location" EntitySet="NodeSet" />
              <End Role="PersonToLocation" EntitySet="LinkSet" />
            </AssociationSet>
          </EntityContainer>
          <EntityType Name="Node" Abstract="true">
            <Key>
              <PropertyRef Name="NodeId" />
            </Key>
            <Property Name="NodeId" Type="Int32" Nullable="false" />
            <Property Name="Name" Type="String" Nullable="false" />
            <Property Name="Description" Type="String" Nullable="true" />
          </EntityType>
          <EntityType Name="Person" BaseType="GraphModel.Node" >
            <NavigationProperty Name="Leaders" Relationship="GraphModel.PersonPersonToPerson_Leader" FromRole="Person" ToRole="PersonToPerson" />
            <NavigationProperty Name="Followers" Relationship="GraphModel.PersonPersonToPerson_Follower" FromRole="Person" ToRole="PersonToPerson" />
            <NavigationProperty Name="Locations" Relationship="GraphModel.Person_PersonToLocation" FromRole="Person" ToRole="PersonToLocation" />
          </EntityType>
          <EntityType Name="Location" BaseType="GraphModel.Node" >
            <NavigationProperty Name="Visitors" Relationship="GraphModel.Location_PersonToLocation" FromRole="Location" ToRole="PersonToLocation" />
          </EntityType>
          <EntityType Name="Link" Abstract="true">
            <Key>
              <PropertyRef Name="LinkId" />
            </Key>
            <Property Name="LinkId" Type="Int32" Nullable="false" />
            <Property Name="Name" Type="String" Nullable="true" />
            <Property Name="Description" Type="String" Nullable="true" />
          </EntityType>
          <EntityType Name="PersonToPerson" BaseType="GraphModel.Link" >
            <NavigationProperty Name="Leader" Relationship="GraphModel.PersonPersonToPerson_Leader" FromRole="PersonToPerson" ToRole="Person" />
            <NavigationProperty Name="Follower" Relationship="GraphModel.PersonPersonToPerson_Follower" FromRole="PersonToPerson" ToRole="Person" />
          </EntityType>
          <EntityType Name="PersonToLocation" BaseType="GraphModel.Link" >
            <NavigationProperty Name="Person" Relationship="GraphModel.Person_PersonToLocation" FromRole="PersonToLocation" ToRole="Person" />
            <NavigationProperty Name="Location" Relationship="GraphModel.Location_PersonToLocation" FromRole="PersonToLocation" ToRole="Location" />
          </EntityType>
          <Association Name="PersonPersonToPerson_Leader">
            <End Type="GraphModel.Person" Role="Person" Multiplicity="1" />
            <End Type="GraphModel.PersonToPerson" Role="PersonToPerson" Multiplicity="*" />
          </Association>
          <Association Name="PersonPersonToPerson_Follower">
            <End Type="GraphModel.Person" Role="Person" Multiplicity="1" />
            <End Type="GraphModel.PersonToPerson" Role="PersonToPerson" Multiplicity="*" />
          </Association>
          <Association Name="Person_PersonToLocation">
            <End Type="GraphModel.Person" Role="Person" Multiplicity="1" />
            <End Type="GraphModel.PersonToLocation" Role="PersonToLocation" Multiplicity="*" />
          </Association>
          <Association Name="Location_PersonToLocation">
            <End Type="GraphModel.Location" Role="Location" Multiplicity="1" />
            <End Type="GraphModel.PersonToLocation" Role="PersonToLocation" Multiplicity="*" />
          </Association>
        </Schema>
      </edmx:ConceptualModels>
      <!-- C-S mapping content -->
      <edmx:Mappings>
        <Mapping xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS" Space="C-S">
          <Alias Key="Model" Value="GraphModel" />
          <Alias Key="Target" Value="GraphModel.Store" />
          <EntityContainerMapping CdmEntityContainer="GraphModelContainer" StorageEntityContainer="GraphModelStoreContainer">
            <EntitySetMapping Name="LinkSet">
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.Link)">
                <MappingFragment StoreEntitySet="Link">
                  <ScalarProperty Name="Description" ColumnName="Description" />
                  <ScalarProperty Name="Name" ColumnName="Name" />
                  <ScalarProperty Name="LinkId" ColumnName="LinkID" />
                </MappingFragment>
              </EntityTypeMapping>
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.PersonToPerson)">
                <MappingFragment StoreEntitySet="Link" >
                  <ScalarProperty Name="LinkId" ColumnName="LinkID" />
                  <Condition ColumnName="LinkTypeDiscriminator" Value="1" />
                </MappingFragment>
              </EntityTypeMapping>
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.PersonToLocation)">
                <MappingFragment StoreEntitySet="Link" >
                  <ScalarProperty Name="LinkId" ColumnName="LinkID" />
                  <Condition ColumnName="LinkTypeDiscriminator" Value="2" />
                </MappingFragment>
              </EntityTypeMapping>
            </EntitySetMapping>
            <EntitySetMapping Name="NodeSet">
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.Node)">
                <MappingFragment StoreEntitySet="Node">
                  <ScalarProperty Name="Description" ColumnName="Description" />
                  <ScalarProperty Name="Name" ColumnName="Name" />
                  <ScalarProperty Name="NodeId" ColumnName="NodeID" />
                </MappingFragment>
              </EntityTypeMapping>
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.Person)">
                <MappingFragment StoreEntitySet="Node" >
                  <ScalarProperty Name="NodeId" ColumnName="NodeID" />
                  <Condition ColumnName="NodeTypeDiscriminator" Value="1" />
                </MappingFragment>
              </EntityTypeMapping>
              <EntityTypeMapping TypeName="IsTypeOf(GraphModel.Location)">
                <MappingFragment StoreEntitySet="Node" >
                  <ScalarProperty Name="NodeId" ColumnName="NodeID" />
                  <Condition ColumnName="NodeTypeDiscriminator" Value="2" />
                </MappingFragment>
              </EntityTypeMapping>
            </EntitySetMapping>
            <AssociationSetMapping Name="PersonPersonToPerson_Follower" TypeName="GraphModel.PersonPersonToPerson_Follower" StoreEntitySet="Link">
              <EndProperty Name="Person">
                <ScalarProperty Name="NodeId" ColumnName="FollowerID" />
              </EndProperty>
              <EndProperty Name="PersonToPerson">
                <ScalarProperty Name="LinkId" ColumnName="LinkID" />
              </EndProperty>
            </AssociationSetMapping>
            <AssociationSetMapping Name="PersonPersonToPerson_Leader" TypeName="GraphModel.PersonPersonToPerson_Leader" StoreEntitySet="Link">
              <EndProperty Name="Person">
                <ScalarProperty Name="NodeId" ColumnName="LeaderID" />
              </EndProperty>
              <EndProperty Name="PersonToPerson">
                <ScalarProperty Name="LinkId" ColumnName="LinkID" />
              </EndProperty>
            </AssociationSetMapping>
            <AssociationSetMapping Name="Person_PersonToLocation" TypeName="GraphModel.Person_PersonToLocation" StoreEntitySet="Link">
              <EndProperty Name="Person">
                <ScalarProperty Name="NodeId" ColumnName="PersonID" />
              </EndProperty>
              <EndProperty Name="PersonToLocation">
                <ScalarProperty Name="LinkId" ColumnName="LinkID" />
              </EndProperty>
            </AssociationSetMapping>
            <AssociationSetMapping Name="Location_PersonToLocation" TypeName="GraphModel.Location_PersonToLocation" StoreEntitySet="Link">
              <EndProperty Name="Location">
                <ScalarProperty Name="NodeId" ColumnName="LocationID" />
              </EndProperty>
              <EndProperty Name="PersonToLocation">
                <ScalarProperty Name="LinkId" ColumnName="LinkID" />
              </EndProperty>
            </AssociationSetMapping>
          </EntityContainerMapping>
        </Mapping>
      </edmx:Mappings>
    </edmx:Runtime>
    <!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
    <edmx:Designer xmlns="http://schemas.microsoft.com/ado/2007/06/edmx">
      <edmx:Connection>
        <DesignerInfoPropertySet>
          <DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
        </DesignerInfoPropertySet>
      </edmx:Connection>
      <edmx:Options>
        <DesignerInfoPropertySet>
          <DesignerProperty Name="ValidateOnBuild" Value="true" />
        </DesignerInfoPropertySet>
      </edmx:Options>
      <!-- Diagram content (shape and connector positions) -->
      <edmx:Diagrams>
        <Diagram Name="GraphModel" ZoomLevel="114" >
          <EntityTypeShape EntityType="GraphModel.Node" Width="1.5" PointX="5.875" PointY="1.375" Height="1.427958984375" />
          <EntityTypeShape EntityType="GraphModel.Person" Width="1.5" PointX="5.875" PointY="3.25" Height="1.4279589843749996" />
          <EntityTypeShape EntityType="GraphModel.Location" Width="1.5" PointX="7.75" PointY="4.625" Height="1.0992643229166665" />
          <InheritanceConnector EntityType="GraphModel.Location">
            <ConnectorPoint PointX="7.375" PointY="2.4176741536458342" />
            <ConnectorPoint PointX="8.5" PointY="2.4176741536458342" />
            <ConnectorPoint PointX="8.5" PointY="4.625" />
          </InheritanceConnector>
          <EntityTypeShape EntityType="GraphModel.Link" Width="1.5" PointX="2.875" PointY="1.375" Height="1.427958984375" />
          <EntityTypeShape EntityType="GraphModel.PersonToPerson" Width="1.75" PointX="2.75" PointY="3.25" Height="1.2636116536458326" />
          <InheritanceConnector EntityType="GraphModel.PersonToPerson" ManuallyRouted="false">
            <ConnectorPoint PointX="3.625" PointY="2.802958984375" />
            <ConnectorPoint PointX="3.625" PointY="3.25" />
          </InheritanceConnector>
          <InheritanceConnector EntityType="GraphModel.Person">
            <ConnectorPoint PointX="6.625" PointY="3.4603483072916683" />
            <ConnectorPoint PointX="6.625" PointY="3.25" />
          </InheritanceConnector>
          <EntityTypeShape EntityType="GraphModel.PersonToLocation" Width="1.875" PointX="0.75" PointY="4.625" Height="1.2636116536458326" />
          <InheritanceConnector EntityType="GraphModel.PersonToLocation">
            <ConnectorPoint PointX="2.875" PointY="2.4176741536458342" />
            <ConnectorPoint PointX="1.65625" PointY="2.4176741536458342" />
            <ConnectorPoint PointX="1.65625" PointY="4.625" />
          </InheritanceConnector>
          <AssociationConnector Association="GraphModel.PersonPersonToPerson_Leader">
            <ConnectorPoint PointX="5.875" PointY="3.8818058268229163" />
            <ConnectorPoint PointX="4.5" PointY="3.8818058268229163" />
          </AssociationConnector>
          <AssociationConnector Association="GraphModel.PersonPersonToPerson_Follower">
            <ConnectorPoint PointX="5.875" PointY="3.5034029134114579" />
            <ConnectorPoint PointX="4.5" PointY="3.5034029134114579" />
          </AssociationConnector>
          <AssociationConnector Association="GraphModel.Person_PersonToLocation">
            <ConnectorPoint PointX="6.625" PointY="4.677958984375" />
            <ConnectorPoint PointX="6.625" PointY="5.0078214863281243" />
            <ConnectorPoint PointX="2.625" PointY="5.0078214863281243" />
          </AssociationConnector>
          <AssociationConnector Association="GraphModel.Location_PersonToLocation">
            <ConnectorPoint PointX="7.75" PointY="5.40018798828125" />
            <ConnectorPoint PointX="2.625" PointY="5.40018798828125" />
          </AssociationConnector>
        </Diagram>
      </edmx:Diagrams>
    </edmx:Designer>
  </edmx:Edmx>

AoA!

EntityModelCodeGenerator create 0..1 to many relation between two tables, Make it 1 to many.

In this kind of case it may be a possible Solution.

Best Regards! Salahuddin