Memetakan kunci komposit menggunakan kode EF terlebih dahulu


115

Tabel server Sql:

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

Bagaimana saya harus memetakan ini dalam kode EF 6 terlebih dahulu?

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

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

Saya telah melihat beberapa contoh di mana Anda harus mengatur urutan untuk setiap kolom, apakah itu wajib?

Apakah ada dokumentasi resmi tentang ini di suatu tempat?


Apakah SomeIda stringatau an int?
Corey Adler

@ IronMan84 Ini adalah string, saya akan memperbaikinya.
loyalflow

Jawaban:


187

Anda pasti perlu memasukkan urutan kolom, jika tidak, bagaimana SQL Server seharusnya tahu mana yang lebih dulu? Inilah yang perlu Anda lakukan dalam kode Anda:

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

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

Anda juga bisa melihat pertanyaan SO ini . Jika Anda menginginkan dokumentasi resmi, saya sarankan untuk melihat situs web resmi EF . Semoga ini membantu.

EDIT: Saya baru saja menemukan entri blog dari Julie Lerman dengan tautan ke semua jenis kebaikan EF 6. Anda dapat menemukan apa pun yang Anda butuhkan di sini .


Bagaimana Anda melakukan ini melalui EntityConfiguration? Saya sebenarnya tidak memiliki entitas untuk tabel gabungan ... Saya hanya memiliki dua entitas dan EntityConfiguration pada salah satunya dengan .Map () untuk menyiapkan pemetaan.
Mir

31
otherwise how is SQL Server supposed to know which one goes first?- mengapa tidak dengan cara yang sama ia mengetahui urutan untuk setiap kolom lainnya?
Davor

1
EF tidak mengetahui urutan kolom lainnya, Anda dapat menyisipkan kolom dalam urutan apapun selama namanya ditentukan. Jika EF mensyaratkan urutan PK komposit, itu harus terkait dengan pengindeksan.
Sylvain Gantois

@Davor Saya membayangkan pembuat EF dapat menggunakan refleksi untuk menyimpulkan urutan kunci / kolom, tetapi mungkin ada pertimbangan kinerja untuk tidak melakukan ini. Saya akan mengambil kekhususan waktu desain daripada kinerja yang lebih lambat setiap hari, terutama di DAL saya.
Jacob Stamm

47

Untuk Memetakan kunci utama komposit menggunakan kerangka kerja entitas kita dapat menggunakan dua pendekatan.

1) Dengan Mengganti Metode OnModelCreating ()

Misalnya: Saya memiliki kelas model bernama VehicleFeature seperti yang ditunjukkan di bawah ini.

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

Kode dalam DBContext saya akan seperti,

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) Dengan Anotasi Data.

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

Silakan lihat tautan di bawah ini untuk informasi lebih lanjut.

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

2) Bagaimana cara menambahkan kunci unik komposit menggunakan EF 6 Fluent Api?


5
FYI untuk EF Core, Opsi # 2 tidak dimungkinkan , "Kunci komposit hanya dapat dikonfigurasi menggunakan Fluent API - konvensi tidak akan pernah menyiapkan kunci komposit dan Anda tidak dapat menggunakan Anotasi Data untuk mengonfigurasinya."
Tobias J

7

Melalui Konfigurasi, Anda dapat melakukan ini:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

lalu di konfigurasi konteks

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

Di mana dalam konfigurasi konteks?
Charlie

Jika Anda mengonfigurasi konteks melalui kode menggunakan Fluent API ... bagian 7 . kelas publik MyContext: DbContext {dilindungi 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

Saya menemukan saya harus menggunakan ModelBuilder daripada DbModelBuilder pada inti dotnet.
kiml42

6

Saya pikir saya akan menambahkan pertanyaan ini karena ini adalah hasil pencarian google teratas.

Seperti yang telah dicatat di komentar, di EF Core tidak ada dukungan untuk menggunakan anotasi (atribut Key) dan harus dilakukan dengan lancar.

Saat saya sedang mengerjakan migrasi besar dari EF6 ke EF Core, ini tidak menyenangkan dan saya mencoba meretasnya dengan menggunakan Reflection untuk mencari atribut Key dan kemudian menerapkannya selama 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);
}

Saya belum sepenuhnya menguji ini dalam semua situasi, tetapi berfungsi dalam tes dasar saya. Semoga ini bisa membantu seseorang

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.