Mapowanie kluczy złożonych przy użyciu najpierw kodu EF

115

Tabela serwera SQL:

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

Jak należy najpierw zamapować to w kodzie EF 6?

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

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

Widziałem kilka przykładów, w których musisz ustawić kolejność dla każdej kolumny, czy to jest wymagane?

Czy jest gdzieś oficjalna dokumentacja na ten temat?

loyalflow
źródło
Czy SomeIda stringczy an int?
Corey Adler
@ IronMan84 To jest ciąg, naprawię to.
loyalflow

Odpowiedzi:

187

Zdecydowanie musisz ustawić kolejność kolumn, w przeciwnym razie skąd SQL Server ma wiedzieć, która z nich jest pierwsza? Oto, co musisz zrobić w swoim kodzie:

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

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

Możesz również spojrzeć na to pytanie SO . Jeśli potrzebujesz oficjalnej dokumentacji, polecam zajrzeć na oficjalną stronę EF . Mam nadzieję że to pomoże.

EDYCJA: Właśnie znalazłem post na blogu Julie Lerman z linkami do wszelkiego rodzaju dobroci EF 6. Można znaleźć co trzeba tutaj .

Corey Adler
źródło
Jak to zrobić za pomocą EntityConfiguration? W rzeczywistości nie mam jednostki dla tabeli łączenia ... Mam tylko dwie jednostki i EntityConfiguration na jednym z nich z .Map () do skonfigurowania mapowania.
Mir
31
otherwise how is SQL Server supposed to know which one goes first?- dlaczego nie w ten sam sposób, w jaki zna kolejność co drugiej kolumny?
Davor
1
EF nie zna kolejności innych kolumn, możesz wstawiać z kolumnami w dowolnej kolejności, o ile określono nazwy. Jeśli EF wymaga kolejności dla złożonej PK, musi to być związane z indeksowaniem.
Sylvain Gantois
@Davor Wyobrażam sobie, że twórcy EF mogli użyć refleksji, aby wywnioskować kolejność klawiszy / kolumn, ale być może istnieją względy wydajnościowe, aby tego nie robić. Każdego dnia wezmę specyfikę czasu projektowania zamiast wolniejszej wydajności, szczególnie w moim DAL.
Jacob Stamm
47

W przypadku klucza podstawowego Mapping Composite przy użyciu Entity Framework możemy użyć dwóch podejść.

1) Przez przesłanianie metody OnModelCreating ()

Na przykład: mam klasę modelu o nazwie VehicleFeature, jak pokazano poniżej.

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

Kod w moim DBContext wyglądałby tak:

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) Według adnotacji danych.

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

Aby uzyskać więcej informacji, skorzystaj z poniższych łączy.

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

2) Jak dodać unikalny klucz złożony za pomocą EF 6 Fluent Api?

Kryszna
źródło
5
FYI dla EF Core, opcja nr 2 nie jest możliwa , „Klucze złożone można skonfigurować tylko przy użyciu interfejsu API Fluent - konwencje nigdy nie skonfigurują klucza złożonego i nie można go skonfigurować za pomocą adnotacji danych”.
Tobias J
7

Poprzez konfigurację możesz to zrobić:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

następnie w kontekście 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);
    }
}
philn5d
źródło
Gdzie w konfiguracji kontekstu?
Charlie
Jeśli konfigurujesz kontekst za pomocą kodu przy użyciu Fluent API ... sekcja 7 . public class MyContext: DbContext {protected override void OnModelCreating (DbModelBuilder modelBuilder) {modelBuilder.Entity <Model1> () .HasRequired (e => e.Model2) .WithMany (e => e.ModelFore1s> newKey). {e.fk_one, e.fk_two}) .WillCascadeOnDelete (false); }}
philn5d
Okazało się, że muszę użyć ModelBuilder zamiast DbModelBuilder w rdzeniu dotnet.
kiml42
6

Pomyślałem, że dodam do tego pytania, ponieważ jest to najlepszy wynik wyszukiwania Google.

Jak zauważono w komentarzach, w EF Core nie ma obsługi używania adnotacji (atrybut klucza) i należy to zrobić z płynnym.

Ponieważ pracowałem nad dużą migracją z EF6 do EF Core, było to niesmaczne, więc próbowałem go zhakować za pomocą odbicia, aby wyszukać atrybut Key, a następnie zastosować go podczas 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);
}

Nie przetestowałem tego w pełni we wszystkich sytuacjach, ale działa to w moich podstawowych testach. Mam nadzieję, że to komuś pomoże

cmorgan091
źródło