Another question about TPH inheritance mapping and how EF decides to map properties into columns.
Suppose that you have the following table:
CREATE TABLE [dbo].[GuiaTransporte](
[IDGuiaTransporte] [int] IDENTITY(1,1) NOT NULL,
[Data] [datetime2](7) NOT NULL,
[IdLocalTrabalhoOrigem] [int] NOT NULL,
[IdLocalTrabalhoDestino] [int] NULL,
[IDFornecedor] [bigint] NULL,
[IdFuncionario] [int] NULL,
/* other columns removed*/
[version] [int] NOT NULL,
CONSTRAINT [PK_GuiaTransporte] PRIMARY KEY CLUSTERED
) ON [PRIMARY]
And you have the following classes:
// base class for derived types
public abstract class GuiaTransporte : Entity, IVersionamento {
public DateTime Data { get; set; }
public string Tecnico { get; set; } = "";
public LocalTrabalho LocalOrigem { get; set; } = new ( );
public DateTime DataTransporte { get; set; }
public string Observacoes { get; private set; } = "";
// other properties removed
}
public class GuiaTransporteLocalTrabalho : GuiaTransporte {
public LocalTrabalho LocalDestino { get; private set; } = new ( );
public Funcionario? Funcionario { get; private set; }
}
public class DocumentoAfetacao : GuiaTransporte {
public Funcionario FuncionarioAfetacao { get; private set; } = new();
public LocalTrabalho LocalDestino { get; private set; } = new();
}
And now, I’m trying to apply the following mappings:
public sealed class GuiaTransporteTypeConfiguration: IEntityTypeConfiguration<GuiaTransporte> {
public void Configure(EntityTypeBuilder<GuiaTransporte> builder){
builder.ToTable("GuiaTransporte");
builder.HasKey(g => g.Id);
builder.Property(g => g.Id).HasColumnName("IdGuiaTransporte");
builder.Property(g => g.Version).IsConcurrencyToken( );
builder.HasDiscriminator(g => g.TipoGuia)
.HasValue<GuiaTransporteLocalTrabalho>(TipoGuiaTransporte.LocalTrabalho)
.HasValue<GuiaTransporteFornecedor>(TipoGuiaTransporte.Fornecedor)
.HasValue<DocumentoAfetacao>(TipoGuiaTransporte.Afetacao);
builder.Property(g => g.TipoGuia)
.HasColumnName("TipoGuiaTransporte");
// other properties
}
}
public sealed class DocumentoAfetacaoTypeConfiguration: IEntityTypeConfiguration<DocumentoAfetacao> {
public void Configure(EntityTypeBuilder<DocumentoAfetacao> builder) {
builder.HasBaseType<GuiaTransporte>( );
builder.HasOne(g => g.FuncionarioAfetacao)
.WithMany( )
.HasForeignKey("IdFuncionario");
builder.Navigation(g => g.FuncionarioAfetacao).AutoInclude( );
builder.HasOne(g => g.LocalDestino)
.WithMany( )
.HasForeignKey("IdLocalTrabalhoDestino");
builder.Navigation(g => g.LocalDestino).AutoInclude( );
}
}
public sealed class GuiaTransporteLocalTrabalhoTypeConfiguration: IEntityTypeConfiguration<GuiaTransporteLocalTrabalho> {
public void Configure(EntityTypeBuilder<GuiaTransporteLocalTrabalho> builder) {
builder.HasBaseType<GuiaTransporte>( );
builder.HasOne(g => g.Funcionario)
.WithMany( )
.HasForeignKey("IdFuncionario");
builder.Navigation(g => g.Funcionario).AutoInclude( );
builder.HasOne(g => g.LocalDestino)
.WithMany( )
.HasForeignKey("IdLocalTrabalhoDestino");
builder.Navigation(g => g.LocalDestino).AutoInclude( );
}
}
As you can see, I have 2 derived types and each one maps its Funcionario
and ´LocalTrabalho` properties to the same table’s column. Well, this works flawlessly with NH but EF seems to ignore one of the mappings, ie, when I try to map each derived type’s navigation property to the same column, only one of the mappings is applied (and EF uses a convention for the other). Here’s the generated SQL for each of the derived types:
/* GuiaTransporte */
INSERT INTO [GuiaTransporte] ([Data], [DataTransporte], [GuiaTransporteLocalTrabalho_IdFuncionario], [GuiaTransporteLocalTrabalho_IdLocalTrabalhoDestino], [IdLocalTrabalhoOrigem], [Observacoes], [Login], [TipoGuiaTransporte], [Version])
OUTPUT INSERTED.[IdGuiaTransporte]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8);
/* DocumentoAfetacao */
INSERT INTO [GuiaTransporte] ([Data], [DataTransporte], [IdFuncionario], [IdLocalTrabalhoDestino], [IdLocalTrabalhoOrigem], [Observacoes], [Login], [TipoGuiaTransporte], [Version])
OUTPUT INSERTED.[IdGuiaTransporte]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8);
As you can see, EF insists on using the typename_foreignkeyname for the second of the derived type’s instead of using the specified foreign key.
Can anyone help? Can’t I map 2 navigation properties from derived types into same column?
Thanks.