Mappatura delle chiavi composite utilizzando prima il codice EF


115

Tabella del server SQL:

SomeId PK varchar(50) not null 
OtherId PK int not null

Come dovrei prima mapparlo nel codice EF 6?

public class MyTable
{
    [Key]
    public string SomeId { get; set; }

    [Key]
    public int OtherId { get; set; }
}

Ho visto alcuni esempi in cui devi impostare l'ordine per ogni colonna, è necessario?

C'è documentazione ufficiale su questo da qualche parte?


È SomeIdun stringo un int?
— Corey Adler,

@ IronMan84 È una stringa, lo aggiusterò.
— loyalflow

Risposte:


187

È assolutamente necessario inserire l'ordine delle colonne, altrimenti come dovrebbe SQL Server sapere quale va per primo? Ecco cosa dovresti fare nel tuo codice:

public class MyTable
{
  [Key, Column(Order = 0)]
  public string SomeId { get; set; }

  [Key, Column(Order = 1)]
  public int OtherId { get; set; }
}

Puoi anche guardare questa domanda SO . Se vuoi la documentazione ufficiale, ti consiglio di guardare il sito web ufficiale di EF . Spero che questo ti aiuti.

EDIT: Ho appena trovato un post sul blog di Julie Lerman con collegamenti a tutti i tipi di bontà di EF 6. Puoi trovare tutto ciò di cui hai bisogno qui .


Come si esegue questa operazione tramite EntityConfiguration? In realtà non ho un'entità per la tabella di join ... Ho solo le due entità e una EntityConfiguration su una di esse con un .Map () per impostare la mappatura.
— Mir

31
otherwise how is SQL Server supposed to know which one goes first?- perché non nello stesso modo in cui conosce l'ordine per ogni altra colonna?
— Davor

1
EF non conosce l'ordine delle altre colonne, puoi inserire con le colonne in qualsiasi ordine purché i nomi siano specificati. Se EF richiede l'ordine per la PK composita, deve essere correlato all'indicizzazione.
— Sylvain Gantois

@Davor Immagino che i creatori di EF avrebbero potuto usare la reflection per dedurre l'ordine di chiave / colonna, ma forse ci sono considerazioni sulle prestazioni per non farlo. Prenderò la specificità in fase di progettazione su prestazioni più lente ogni giorno, specialmente nel mio DAL.
— Jacob Stamm

47

Per la mappatura della chiave primaria composita utilizzando Entity framework possiamo utilizzare due approcci.

1) Sovrascrivendo il metodo OnModelCreating ()

Ad esempio: ho la classe del modello denominata VehicleFeature come mostrato di seguito.

public class VehicleFeature
{
    public int VehicleId { get; set; }
    public int FeatureId{get;set;}
    public Vehicle Vehicle{get;set;}
    public Feature Feature{get;set;}
}

Il codice nel mio DBContext sarebbe come,

public class VegaDbContext : DbContext
{
    public DbSet<Make> Makes{get;set;}

    public DbSet<Feature> Features{get;set;}
    public VegaDbContext(DbContextOptions<VegaDbContext> options):base(options)        
    {           

    }
    // we override the OnModelCreating method here.
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<VehicleFeature>().HasKey(vf=> new {vf.VehicleId, vf.FeatureId});
    }
}

2) Per annotazioni dati.

public class VehicleFeature
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
    [Key]
    public int VehicleId { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]   
    [Key]
    public int FeatureId{get;set;}
    public Vehicle Vehicle{get;set;}
    public Feature Feature{get;set;}
}

Fare riferimento ai collegamenti sottostanti per ulteriori informazioni.

1) https://msdn.microsoft.com/en-us/library/jj591617(v=vs.113).aspx

2) Come aggiungere una chiave univoca composita utilizzando EF 6 Fluent Api?


5
Cordiali saluti per EF Core, l'opzione n. 2 non è possibile , "Le chiavi composite possono essere configurate solo utilizzando l'API Fluent: le convenzioni non configureranno mai una chiave composita e non è possibile utilizzare le annotazioni dei dati per configurarne una".
— Tobias J

7

Tramite Configurazione, puoi farlo:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

quindi nel contesto config

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Model1>()
            .HasRequired(e => e.Model2)
            .WithMany(e => e.Model1s)
            .HasForeignKey(e => new { e.fk_one, e.fk_two })
            .WillCascadeOnDelete(false);
    }
}

Dove nel contesto config?
— Charlie,

Se stai configurando il contesto tramite codice utilizzando Fluent API ... sezione 7 . classe pubblica MyContext: DbContext {protected override void OnModelCreating (DbModelBuilder modelBuilder) {modelBuilder.Entity <Model1> () .HasRequired (e => e.Model2) .WithMany (e => e.Model1s> .HasForeign {e.fk_one, e.fk_two}) .WillCascadeOnDelete (false); }}
— philn5d

Ho scoperto che dovevo usare ModelBuilder invece di DbModelBuilder su dotnet core.
— kiml42

6

Ho pensato di aggiungere a questa domanda in quanto è il primo risultato di ricerca di Google.

Come è stato notato nei commenti, in EF Core non è disponibile il supporto per l'utilizzo delle annotazioni (attributo Key) e deve essere eseguito in modo fluente.

Dato che stavo lavorando a una migrazione di grandi dimensioni da EF6 a EF Core, questo non era raccomandabile e quindi ho provato ad hackerarlo usando Reflection per cercare l'attributo Key e quindi applicarlo durante OnModelCreating

// get all composite keys (entity decorated by more than 1 [Key] attribute
foreach (var entity in modelBuilder.Model.GetEntityTypes()
    .Where(t => 
        t.ClrType.GetProperties()
            .Count(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute))) > 1))
{
    // get the keys in the appropriate order
    var orderedKeys = entity.ClrType
        .GetProperties()
        .Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute)))
        .OrderBy(p => 
            p.CustomAttributes.Single(x => x.AttributeType == typeof(ColumnAttribute))?
                .NamedArguments?.Single(y => y.MemberName == nameof(ColumnAttribute.Order))
                .TypedValue.Value ?? 0)
        .Select(x => x.Name)
        .ToArray();

    // apply the keys to the model builder
    modelBuilder.Entity(entity.ClrType).HasKey(orderedKeys);
}

Non l'ho testato completamente in tutte le situazioni, ma funziona nei miei test di base. Spero che questo aiuti qualcuno

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.