การแมปคีย์คอมโพสิตโดยใช้รหัส EF ก่อน


115

ตารางเซิร์ฟเวอร์ SQL:

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

ฉันจะแมปสิ่งนี้ในโค้ด EF 6 ก่อนได้อย่างไร

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

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

ฉันเคยเห็นตัวอย่างบางส่วนที่คุณต้องตั้งลำดับสำหรับแต่ละคอลัมน์จำเป็นหรือไม่

มีเอกสารอย่างเป็นทางการเกี่ยวกับเรื่องนี้หรือไม่?


คือหรือ? SomeIdstringint
Corey Adler

@ IronMan84 มันเป็นสตริงฉันจะแก้ไข
ภักดีโฟลว์

คำตอบ:


187

คุณต้องวางลำดับคอลัมน์อย่างแน่นอนมิฉะนั้น SQL Server ควรจะรู้ได้อย่างไรว่าอันไหนถึงก่อน? นี่คือสิ่งที่คุณต้องทำในโค้ดของคุณ:

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

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

คุณยังสามารถดูคำถาม SOนี้ หากคุณต้องการเอกสารอย่างเป็นทางการผมจะขอแนะนำให้ดูที่เว็บไซต์อย่างเป็นทางการของ EF หวังว่านี่จะช่วยได้

แก้ไข: ฉันเพิ่งพบบล็อกโพสต์ของ Julie Lerman พร้อมลิงก์ไปยัง EF 6 ความดีทุกประเภท คุณสามารถค้นหาสิ่งที่คุณต้องการที่นี่


คุณทำสิ่งนี้ผ่าน EntityConfiguration ได้อย่างไร? ฉันไม่มีเอนทิตีสำหรับตารางการเข้าร่วมจริงๆ ... ฉันมีเพียงสองเอนทิตีและเอนทิตีคอนฟิกูเรชันหนึ่งในนั้นโดยมี. แผนที่ () เพื่อตั้งค่าการแมป
ร์

31
otherwise how is SQL Server supposed to know which one goes first?- ทำไมไม่เหมือนกันที่รู้ลำดับสำหรับคอลัมน์อื่น ๆ
Davor

1
EF ไม่ทราบลำดับของคอลัมน์อื่นคุณสามารถแทรกด้วยคอลัมน์ในลำดับใดก็ได้ตราบเท่าที่ระบุชื่อ หาก EF ต้องการคำสั่งสำหรับ PK แบบผสมจะต้องเกี่ยวข้องกับการจัดทำดัชนี
Sylvain Gantois

@ ฉันคิดว่าผู้สร้าง EF อาจใช้การสะท้อนกลับเพื่อสรุปลำดับคีย์ / คอลัมน์ แต่อาจมีข้อควรพิจารณาเกี่ยวกับประสิทธิภาพที่ไม่ทำเช่นนี้ ฉันจะใช้ความเฉพาะเจาะจงของเวลาออกแบบมากกว่าประสิทธิภาพที่ช้าลงทุกวันโดยเฉพาะใน DAL ของฉัน
Jacob Stamm

47

สำหรับการแม็ปคีย์หลักแบบผสมโดยใช้เอนทิตีเฟรมเวิร์กเราสามารถใช้สองวิธี

1) โดยการแทนที่วิธี OnModelCreating ()

เช่นฉันมีโมเดลคลาสชื่อ VehicleFeature ดังที่แสดงด้านล่าง

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

รหัสใน DBContext ของฉันจะเป็นอย่างไร

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) โดยคำอธิบายประกอบข้อมูล

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

โปรดดูลิงค์ด้านล่างสำหรับข้อมูลเพิ่มเติม

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

2) จะเพิ่มคีย์เฉพาะแบบผสมโดยใช้ EF 6 Fluent Api ได้อย่างไร


5
FYI สำหรับ EF Core ตัวเลือก # 2 เป็นไปไม่ได้ "คีย์คอมโพสิตสามารถกำหนดค่าได้โดยใช้ Fluent API เท่านั้น - ข้อกำหนดจะไม่ตั้งค่าคีย์ผสมและคุณไม่สามารถใช้คำอธิบายประกอบข้อมูลเพื่อกำหนดค่าได้"
Tobias J

7

ผ่านการกำหนดค่าคุณสามารถทำได้:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

จากนั้นในการกำหนดค่าบริบท

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

กำหนดค่าบริบทอยู่ที่ไหน
Charlie

หากคุณกำลังกำหนดค่าบริบทผ่านโค้ดโดยใช้ Fluent API ... ส่วนที่ 7 . คลาสสาธารณะ 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 (เท็จ); }}
philn5d

ฉันพบว่าฉันต้องใช้ ModelBuilder แทน DbModelBuilder บน dotnet core
kiml42

6

ฉันคิดว่าฉันจะเพิ่มคำถามนี้เนื่องจากเป็นผลการค้นหาอันดับต้น ๆ ของ Google

ตามที่ได้ระบุไว้ในความคิดเห็นแล้วใน EF Core ไม่มีการรองรับการใช้คำอธิบายประกอบ (Key attribute) และต้องทำอย่างคล่องแคล่ว

เนื่องจากฉันกำลังดำเนินการย้ายข้อมูลจำนวนมากจาก EF6 ไปยัง EF Core สิ่งนี้จึงไม่น่าสนใจดังนั้นฉันจึงพยายามแฮ็กโดยใช้ Reflection เพื่อค้นหาแอตทริบิวต์ Key จากนั้นนำไปใช้ในระหว่าง 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);
}

ฉันยังไม่ได้ทดสอบสิ่งนี้อย่างสมบูรณ์ในทุกสถานการณ์ แต่ใช้ได้ในการทดสอบพื้นฐานของฉัน หวังว่านี่จะช่วยใครบางคนได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.