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.