Zuordnen zusammengesetzter Schlüssel zuerst mit EF-Code


115

SQL Server-Tabelle:

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

Wie soll ich dies zuerst in EF 6-Code abbilden?

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

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

Ich habe einige Beispiele gesehen, in denen Sie die Reihenfolge für jede Spalte festlegen müssen. Ist das erforderlich?

Gibt es irgendwo offizielle Unterlagen dazu?


Ist SomeIdein stringoder ein int?
Corey Adler

@ IronMan84 Es ist eine Zeichenfolge, das werde ich beheben.
Loyalflow

Antworten:


186

Sie müssen auf jeden Fall die Spaltenreihenfolge eingeben, sonst wie soll SQL Server wissen, welche zuerst ausgeführt wird? Folgendes müssten Sie in Ihrem Code tun:

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

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

Sie können sich auch diese SO-Frage ansehen . Wenn Sie eine offizielle Dokumentation wünschen, würde ich empfehlen, die offizielle EF-Website zu besuchen . Hoffe das hilft.

EDIT: Ich habe gerade einen Blog-Beitrag von Julie Lerman mit Links zu allen Arten von EF 6-Güte gefunden. Sie können alles , was Sie brauchen , finden Sie hier .


Wie machen Sie das über eine EntityConfiguration? Ich habe eigentlich keine Entität für die Join-Tabelle ... Ich habe nur die beiden Entitäten und eine EntityConfiguration auf einer von ihnen mit einer .Map (), um die Zuordnung einzurichten.
Mir

31
otherwise how is SQL Server supposed to know which one goes first?- warum nicht auf die gleiche Weise die Reihenfolge für jede zweite Spalte kennen?
Davor

1
EF kennt die Reihenfolge anderer Spalten nicht. Sie können Spalten in beliebiger Reihenfolge einfügen, solange die Namen angegeben sind. Wenn EF die Reihenfolge für die zusammengesetzte PK erfordert, muss sie sich auf die Indizierung beziehen.
Sylvain Gantois

@Davor Ich stelle mir vor, dass die EF-Ersteller mithilfe der Reflexion auf die Reihenfolge der Schlüssel / Spalten schließen konnten, aber möglicherweise gibt es Leistungsüberlegungen, wenn Sie dies nicht tun. Ich werde jeden Tag die Design-Time-Spezifität über die langsamere Leistung nehmen, insbesondere in meinem DAL.
Jacob Stamm

47

Für die Zuordnung des zusammengesetzten Primärschlüssels mithilfe des Entity-Frameworks können zwei Ansätze verwendet werden.

1) Durch Überschreiben der OnModelCreating () -Methode

Zum Beispiel: Ich habe die Modellklasse VehicleFeature wie unten gezeigt.

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

Der Code in meinem DBContext wäre wie folgt:

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) Durch Datenanmerkungen.

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;}
}

Weitere Informationen finden Sie unter den folgenden Links.

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

2) Wie füge ich mit EF 6 Fluent Api einen zusammengesetzten eindeutigen Schlüssel hinzu?


5
Zu Ihrer Information für EF Core, Option 2 ist nicht möglich . "Zusammengesetzte Schlüssel können nur mit der Fluent-API konfiguriert werden. Konventionen richten niemals einen zusammengesetzten Schlüssel ein und Sie können keine Datenanmerkungen verwenden, um einen zu konfigurieren."
Tobias J

7

Über die Konfiguration können Sie Folgendes tun:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

dann im Kontext 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);
    }
}

Wo in der Kontextkonfiguration?
Charlie

Wenn Sie den Kontext über Code mithilfe der Fluent API konfigurieren ... Abschnitt 7 . öffentliche Klasse MyContext: DbContext {protected override void OnModelCreating (DbModelBuilder modelBuilder) {modelBuilder.Entity <Model1> () .HasRequired (e => e.Model2) .WithMany (e => e.Model1s) .HasForeignK {e.fk_one, e.fk_two}) .WillCascadeOnDelete (false); }}
philn5d

Ich musste ModelBuilder anstelle von DbModelBuilder auf dem Dotnet-Core verwenden.
Kiml42

6

Ich dachte, ich würde diese Frage ergänzen, da es das beste Google-Suchergebnis ist.

Wie in den Kommentaren erwähnt, gibt es in EF Core keine Unterstützung für die Verwendung von Anmerkungen (Schlüsselattribut) und dies muss fließend erfolgen.

Da ich an einer großen Migration von EF6 zu EF Core arbeitete, war dies unappetitlich. Daher habe ich versucht, sie mithilfe von Reflection zu hacken, um nach dem Schlüsselattribut zu suchen und es dann während OnModelCreating anzuwenden

// 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);
}

Ich habe dies nicht in allen Situationen vollständig getestet, aber es funktioniert in meinen Basistests. Hoffe das hilft jemandem

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.