Fluent Nxn mapping of Classes with composite key

Asked

Viewed 357 times

3

I have two classes that have composite primary keys, example:

Cliente:

public class Cliente
{
    public int EscritorioId { get; set; }
    public virtual Escritorio Escritorio { get; set; }

    public int Id { get; set; }
}

public class ClienteMapping : EntityTypeConfiguration<Cliente>
{
    public ClienteMapping()
    {
        HasKey(x => new { x.Id, x.EscritorioId });
    }
}

Documento:

public class Documento
{
    public int EscritorioId { get; set; }
    public virtual Escritorio Escritorio { get; set; }

    public int Id { get; set; }

    public virtual ICollection<Cliente> ClientesComAcesso { get; set; }
}

And in class mapping Documento I have a mapping Nxn:

public class DocumentoMapping: EntityTypeConfiguration<Documento>
{
    public DocumentoMapping()
    {
        HasKey(x => new { x.EscritorioId, x.Id });

        HasMany(x => x.Clientes)
            .WithMany()
            .Map(m => 
            {
                x.MapLeftKey("EscritorioId", "DocumentoId");
                x.MapLeftKey("EscritorioId", "ClienteId");
                x.ToTable("DocumentoClientes");
            });
    }
}

Because a customer can be a recipient/have access to multiple documents.

However, when trying to generate the Migrations for that case I get the following error:

The specified Association Foreign key Columns 'Documentoid' are invalid. The number of Columns specified must match the number of Primary key Columns.

Trying to give another name to the composite keys, like Documento_EscritorioId and Cliente_EscritorioId, for example:

HasMany(x => x.Clientes)
    .WithMany()
    .Map(m => 
    {
        x.MapLeftKey("Documento_EscritorioId", "DocumentoId");
        x.MapLeftKey("Cliente_EscritorioId", "ClienteId");
        x.ToTable("DocumentoClientes");
    });

It works, but in this case we have a redundancy.

What is the correct way to do this mapping?

1 answer

2


I see no need to use EntityTypeConfiguration for something so simple. The Models can stay like this:

public class Cliente
{
    [Key]
    public int Id { get; set; }
    public int EscritorioId { get; set; }

    public virtual Escritorio Escritorio { get; set; }
    public virtual ICollection<DocumentoCliente> DocumentosComAcesso { get; set; }
}

public class Documento
{
    public int Id { get; set; }
    public int EscritorioId { get; set; }

    public virtual Escritorio Escritorio { get; set; }    
    public virtual ICollection<DocumentoCliente> ClientesComAcesso { get; set; }
}

I find it more interesting to create the associative entity, even if it initially seems long. The gain in development is greater, because you can put more fields inherent in the association itself:

public class DocumentoCliente 
{
    [Key]
    public int DocumentoClienteId { get; set; }
    [Index("IUQ_DocumentoCliente_DocumentoId_ClienteId", IsUnique = true, Order = 1)]
    public int DocumentoId { get; set; }
    [Index("IUQ_DocumentoCliente_DocumentoId_ClienteId", IsUnique = true, Order = 2)]
    public int ClienteId { get; set; }

    public virtual Documento Documento { get; set; }
    public virtual Cliente Cliente { get; set; }
}

[Index], introduced in this form from the Entity Framework 6.1.0, ensures the uniqueness of the associative record. Additional validations may be required in the application to avoid strange key duplicity errors for the user.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.