【问题标题】:Mapping composite keys using EF code first首先使用 EF 代码映射复合键
【发布时间】:2020-04-07 03:23:53
【问题描述】:

Sql server 表:

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

我见过一些例子,你必须为每列设置顺序,这是必需的吗?

在某处有这方面的官方文档吗?

【问题讨论】:

  • SomeIdstring 还是 int
  • @IronMan84 这是一个字符串,我会修复它。

标签: c# sql-server entity-framework entity-framework-6


【解决方案1】:

您肯定需要按列顺序排列,否则 SQL Server 应该如何知道哪个排在前面?以下是您需要在代码中执行的操作:

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

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

您也可以查看this SO question。如果您想要官方文档,我建议您查看official EF website。希望这会有所帮助。

编辑:我刚刚发现 Julie Lerman 的一篇博文,其中包含各种 EF 6 优点的链接。你可以找到任何你需要的东西here

【讨论】:

  • 如何通过 EntityConfiguration 做到这一点?我实际上没有连接表的实体......我只有两个实体和一个实体配置,其中一个带有 .Map() 来设置映射。
  • otherwise how is SQL Server supposed to know which one goes first? - 为什么不以同样的方式知道其他列的顺序?
  • EF 不知道其他列的顺序,只要指定名称,您可以按任何顺序插入列。如果 EF 需要复合 PK 的顺序,它必须与索引相关。
  • @Davor 我想 EF 创建者可以使用反射来推断键/列顺序,但也许不这样做会考虑性能。我每天都会考虑设计时的特殊性而不是较慢的性能,尤其是在我的 DAL 中。
  • 我认为提前订购是有意义的。如果有一天你重新排序这些属性,你会很生气地发现实体框架停止工作。
【解决方案2】:

对于使用实体框架映射复合主键,我们可以使用两种方法。

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) How to add a composite unique key using EF 6 Fluent Api?

【讨论】:

  • EF Core 仅供参考,选项 #2 是 not possible,“只能使用 Fluent API 配置复合键 - 约定永远不会设置复合键,您不能使用数据注释来配置复合键。”
【解决方案3】:

我想我会补充这个问题,因为它是谷歌搜索结果的热门。

正如在 cmets 中所指出的,在 EF Core 中不支持使用注解(Key 属性),必须使用 fluent 来完成。

由于我正在进行从 EF6 到 EF Core 的大规模迁移,这令人讨厌,因此我尝试通过使用反射来查找 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);
}

我没有在所有情况下都对此进行全面测试,但它在我的基本测试中有效。希望这可以帮助某人

【讨论】:

    【解决方案4】:

    通过配置,你可以这样做:

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

    【讨论】:

    • 上下文配置在哪里?
    • 如果您使用 Fluent API 通过代码配置上下文...section 7。公共类 MyContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasRequired(e => e.Model2) .WithMany(e => e.Model1s) .HasForeignKey(e => new { e.fk_one, e.fk_two }) .WillCascadeOnDelete(false); } }
    • 我发现我必须在 dotnet core 上使用 ModelBuilder 而不是 DbModelBuilder。
    猜你喜欢
    • 2011-10-26
    • 2011-12-14
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2011-10-06
    相关资源
    最近更新 更多