ADO EF - Associazioni di associazioni di errori tra tipi derivati in TPH

c# entity-framework orm

Domanda

sfondo

Sto scrivendo una libreria di accesso ai dati utilizzando ADO Entity Framework in Visual Studio 2008 SP1 utilizzando .NET Framework 3.5 SP1. Sto cercando di creare associazioni tra due entità che sono entrambe derivate da un tipo astratto. Sto rappresentando entrambe le gerarchie di ereditarietà dell'entità utilizzando Table Per Hierarchy (TPH), il che significa che ci sono solo due tabelle, una per ogni gerarchia di ereditarietà dell'entità.

NOTA È possibile utilizzare Table Per Type (TPT) per evitare questo problema, ma viene fornito con i propri svantaggi. Vedi qui e qui per maggiori dettagli quando si sceglie tra i modelli di persistenza dell'eredità.

Ecco uno screenshot della vista Designer del Modello entità:

Vista di progettazione del modello di entità in Visual Studio 2008 SP1

Ed ecco uno screenshot dello schema del database:

Schema del database

ipotesi

Quando si creano associazioni in ADO Entity Framework Designer tra tipi derivati modellati con TPH utilizzando Visual Studio 2008 SP1 e .NET Framework 3.5 SP1, è probabile che venga visualizzato quanto segue "Errore 3034: due entità con chiavi diverse sono associate allo stesso riga. Assicurarsi che questi due frammenti di mappatura non eseguano la mappatura di due gruppi di entità con chiavi sovrapposte allo stesso gruppo di righe. "

Sulla base di ciò che ho letto online , per risolvere questo problema, devi aggiungere una Condizione all'associazione sulla chiave esterna in questo modo:

<Condition ColumnName="Endpoint1" IsNull="false" />

Ecco uno screenshot di questa modifica per l'associazione PersonPersonToPerson1:

Visual Studio 2008 SP1 Modifica di GraphModel.edmx

vincoli

  • Le classi base di ogni gerarchia (cioè Nodo e Link) devono essere astratte.
  • Le proprietà di navigazione delle associazioni tra due tipi derivati devono essere distinguibili dal tipo di collegamento (ad es. PersonToPerson e PersonToLocation). Ciò significa che non è possibile creare le associazioni tra le classi base astratte Link e Node.

Problema:

Quando creo il modello di entità come descritto sopra e aggiungo le condizioni a AssociationMappings come descritto nei Presupposti sopra, ricevo un "Errore 3023" quando costruisco / convalido il modello.

Error   1   Error 3023: Problem in Mapping Fragments starting at lines 146, 153, 159, 186, 195, 204, 213: Column Link.Endpoint1 has no default value and is not nullable. A column value is required to store entity data.
An Entity with Key (PK) will not round-trip when:
((PK is NOT in 'LinkSet' EntitySet OR PK does NOT play Role 'PersonToPerson' in AssociationSet 'PersonPersonToPerson1') AND (PK is in 'LinkSet' EntitySet OR PK plays Role 'PersonToPerson' in AssociationSet 'PersonPersonToPerson1' OR PK plays Role 'PersonToPerson' in AssociationSet 'PersonPersonToPerson'))
C:\Documents and Settings\Demo\My Documents\Visual Studio 2008\Projects\GraphExample2.BusinessEntities\GraphExample2.BusinessEntities\GraphModel.edmx   147 15  GraphExample2.BusinessEntities

La cosa su cui Entity Framework viene bloccato nello scenario sopra riportato è che ci sono due proprietà che vengono mappate sulle stesse chiavi esterne. Ad esempio, la colonna e la chiave esterna per Endpoint1 sono associate alla proprietà Person nel tipo derivato PersonToLocation ed è associata alla proprietà Leader nel tipo derivato di PersonToPerson.

Non capisco perché questo è un problema. Poiché le proprietà Leader / Follower sono solo nel tipo derivato di PersonToPerson - non di qualsiasi altro tipo derivato o tipo di base - e lo stesso vale per la proprietà Persona / Posizione, perché il campo TypeDiscriminator non è sufficiente per determinare quale impostare una data riga appartiene?

A me sembra che, se si ha a che fare con un oggetto in cui TypeDiscriminator = 1, si posiziona Endpoint1 in Leader e Endpoint2 in follower. Allo stesso modo, se si ha a che fare con un oggetto in cui TypeDiscriminator = 2, si posiziona Endpoint1 in Person ed Endpoint2 in Location.

Domanda:

Come si risolve l'errore 3023 per consentire a queste associazioni di verificarsi?

O

Come si crea il tipo di associazioni in ADO Entity Framework che ho descritto sopra?

Riferimenti:

Codice

SQL:

USE [GraphExample2]
GO
/****** Object:  Table [dbo].[Node]    Script Date: 02/17/2009 14:36:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Node](
    [NodeID] [int] 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/17/2009 14:36:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Link](
    [LinkID] [int] NOT NULL,
    [LinkTypeDiscriminator] [int] NOT NULL,
    [Endpoint1] [int] NOT NULL,
    [Endpoint2] [int] NOT 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_Endpoint1]    Script Date: 02/17/2009 14:36:12 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Endpoint1] FOREIGN KEY([Endpoint1])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Endpoint1]
GO
/****** Object:  ForeignKey [FK_Link_Node_Endpoint2]    Script Date: 02/17/2009 14:36:12 ******/
ALTER TABLE [dbo].[Link]  WITH CHECK ADD  CONSTRAINT [FK_Link_Node_Endpoint2] FOREIGN KEY([Endpoint2])
REFERENCES [dbo].[Node] ([NodeID])
GO
ALTER TABLE [dbo].[Link] CHECK CONSTRAINT [FK_Link_Node_Endpoint2]
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_Endpoint1" Association="GraphModel.Store.FK_Link_Node_Endpoint1">
            <End Role="Node" EntitySet="Node" />
            <End Role="Link" EntitySet="Link" />
          </AssociationSet>
          <AssociationSet Name="FK_Link_Node_Endpoint2" Association="GraphModel.Store.FK_Link_Node_Endpoint2">
            <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" />
          <Property Name="LinkTypeDiscriminator" Type="int" Nullable="false" />
          <Property Name="Endpoint1" Type="int" Nullable="false" />
          <Property Name="Endpoint2" Type="int" Nullable="false" />
          <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" />
          <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_Endpoint1">
          <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="1" />
          <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Node">
              <PropertyRef Name="NodeID" />
            </Principal>
            <Dependent Role="Link">
              <PropertyRef Name="Endpoint1" />
            </Dependent>
          </ReferentialConstraint>
        </Association>
        <Association Name="FK_Link_Node_Endpoint2">
          <End Role="Node" Type="GraphModel.Store.Node" Multiplicity="1" />
          <End Role="Link" Type="GraphModel.Store.Link" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Node">
              <PropertyRef Name="NodeID" />
            </Principal>
            <Dependent Role="Link">
              <PropertyRef Name="Endpoint2" />
            </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" Association="GraphModel.PersonPersonToPerson">
            <End Role="Person" EntitySet="NodeSet" />
            <End Role="PersonToPerson" EntitySet="LinkSet" />
          </AssociationSet>
          <AssociationSet Name="PersonPersonToPerson1" Association="GraphModel.PersonPersonToPerson1">
            <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" FromRole="Person" ToRole="PersonToPerson" />
          <NavigationProperty Name="Followers" Relationship="GraphModel.PersonPersonToPerson1" 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" FromRole="PersonToPerson" ToRole="Person" />
          <NavigationProperty Name="Follower" Relationship="GraphModel.PersonPersonToPerson1" 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">
          <End Type="GraphModel.Person" Role="Person" Multiplicity="1" />
          <End Type="GraphModel.PersonToPerson" Role="PersonToPerson" Multiplicity="*" />
        </Association>
        <Association Name="PersonPersonToPerson1">
          <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="PersonPersonToPerson1" TypeName="GraphModel.PersonPersonToPerson1" StoreEntitySet="Link">
            <EndProperty Name="Person">
              <ScalarProperty Name="NodeId" ColumnName="Endpoint1" />
            </EndProperty>
            <EndProperty Name="PersonToPerson">
              <ScalarProperty Name="LinkId" ColumnName="LinkID" />
            </EndProperty>
            <Condition ColumnName="Endpoint1" IsNull="false" />
          </AssociationSetMapping>
          <AssociationSetMapping Name="PersonPersonToPerson" TypeName="GraphModel.PersonPersonToPerson" StoreEntitySet="Link">
            <EndProperty Name="Person">
              <ScalarProperty Name="NodeId" ColumnName="Endpoint2" />
            </EndProperty>
            <EndProperty Name="PersonToPerson">
              <ScalarProperty Name="LinkId" ColumnName="LinkID" />
            </EndProperty>
            <Condition ColumnName="Endpoint2" IsNull="false" />
          </AssociationSetMapping>
          <AssociationSetMapping Name="Person_PersonToLocation" TypeName="GraphModel.Person_PersonToLocation" StoreEntitySet="Link">
            <EndProperty Name="Person">
              <ScalarProperty Name="NodeId" ColumnName="Endpoint1" />
            </EndProperty>
            <EndProperty Name="PersonToLocation">
              <ScalarProperty Name="LinkId" ColumnName="LinkID" />
            </EndProperty>
            <Condition ColumnName="Endpoint1" IsNull="false" />
          </AssociationSetMapping>
          <AssociationSetMapping Name="Location_PersonToLocation" TypeName="GraphModel.Location_PersonToLocation" StoreEntitySet="Link">
            <EndProperty Name="Location">
              <ScalarProperty Name="NodeId" ColumnName="Endpoint2" />
            </EndProperty>
            <EndProperty Name="PersonToLocation">
              <ScalarProperty Name="LinkId" ColumnName="LinkID" />
            </EndProperty>
            <Condition ColumnName="Endpoint2" IsNull="false" />
          </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.0889794921875" />
          <ConnectorPoint PointX="8.5" PointY="2.0889794921875" />
          <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.625" PointY="3.125" Height="0.9349169921875" />
        <InheritanceConnector EntityType="GraphModel.PersonToPerson">
          <ConnectorPoint PointX="3.625" PointY="2.802958984375" />
          <ConnectorPoint PointX="3.625" PointY="3.125" />
        </InheritanceConnector>
        <InheritanceConnector EntityType="GraphModel.Person">
          <ConnectorPoint PointX="6.625" PointY="2.802958984375" />
          <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.0889794921875" />
          <ConnectorPoint PointX="1.65625" PointY="2.0889794921875" />
          <ConnectorPoint PointX="1.65625" PointY="4.625" />
        </InheritanceConnector>
        <AssociationConnector Association="GraphModel.PersonPersonToPerson">
          <ConnectorPoint PointX="5.875" PointY="3.8193058268229163" />
          <ConnectorPoint PointX="4.375" PointY="3.8193058268229163" />
        </AssociationConnector>
        <AssociationConnector Association="GraphModel.PersonPersonToPerson1">
          <ConnectorPoint PointX="5.875" PointY="3.4721529134114579" />
          <ConnectorPoint PointX="4.375" PointY="3.4721529134114579" />
        </AssociationConnector>
        <AssociationConnector Association="GraphModel.Person_PersonToLocation">
          <ConnectorPoint PointX="6.625" PointY="4.677958984375" />
          <ConnectorPoint PointX="6.625" PointY="5.1875" />
          <ConnectorPoint PointX="2.625" PointY="5.1875" />
        </AssociationConnector>
        <AssociationConnector Association="GraphModel.Location_PersonToLocation">
          <ConnectorPoint PointX="7.75" PointY="5.4791666666666661" />
          <ConnectorPoint PointX="2.625" PointY="5.4791666666666661" />
        </AssociationConnector>
      </Diagram>
    </edmx:Diagrams>
  </edmx:Designer>
</edmx:Edmx>

Risposta accettata

Possibile soluzione

  1. Creare una colonna separata per ogni associazione tra tipi derivati e rendere nullable ognuna di queste colonne
  2. Crea una chiave esterna tra ognuna di queste nuove colonne e la tabella delle chiavi primaria.
  3. Mappare ciascuna associazione nel proprio modello entità su una colonna specifica e univoca e una chiave esterna in modo che ogni colonna e chiave esterna vengano utilizzate una sola volta.

I problemi

Questa è una soluzione piuttosto indesiderabile perché esplode il numero di colonne di cui hai bisogno.

  • Altre colonne : l'aggiunta di una colonna per ogni associazione tra tipi derivati genera un'esplosione sul numero di colonne.
  • Colonne vuote Nel caso di TPH, significa che avrai un sacco di colonne vuote nella tua tabella.
  • SQL JOIN - Passare da TPH a TPT per evitare il numero di colonne vuote comporta la necessità per EF di utilizzare un JOIN che dovrà verificarsi molto frequentemente (quasi ogni volta che si affronta uno qualsiasi dei tipi derivati).
  • Refactoring Se in futuro aggiungerai un tipo derivato, non dovrai solo aggiornare il tuo modello Entity (* .edmx) e il suo mapping ma dovrai anche modificare lo schema del database aggiungendo ulteriori colonne!

Esempio

Per l'esempio Link / Node sopra, lo schema del database risultante sarebbe simile a questo:

Schema di esempio del diagramma di soluzione del campione grafico http://img230.imageshack.us/img230/1628/graphexampledatabasewor.th.png


Codice

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>

Risposta popolare

AoA!

EntityModelCodeGenerator crea 0..1 a molte relazioni tra due tabelle, rendendola da 1 a molte .

In questo tipo di casi potrebbe essere una possibile soluzione.

I migliori saluti! Salahuddin



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché