首先使用EF代码映射复合键


115

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

我看过一些示例,您必须为每个列设置顺序,这是必需的吗?

在某处有官方文件吗?


SomeIda string还是an int
科里·阿德勒

@ IronMan84这是一个字符串,我会解决。
loyalflow 2013年

Answers:


186

您肯定需要按列顺序输入,否则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做到这一点?我实际上没有用于联接表的实体...我只有两个实体和其中一个具有EntityConfiguration的.Configuration()来设置映射。
和平

31
otherwise how is SQL Server supposed to know which one goes first?-为什么不以相同的方式知道每隔一列的顺序?
Davor

1
EF不知道其他列的顺序,只要指定名称,您就可以按任何顺序插入列。如果EF需要复合PK的顺序,则它必须与索引相关。
Sylvain Gantois

@Davor我想像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/zh-cn/library/jj591617(v=vs.113 ) .aspx

2)如何使用EF 6 Fluent Api添加复合唯一键?


5
EF Core的FYI,选项#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);
    }
}

在上下文配置中的哪里?
查理

如果您正在使用Fluent API ...通过代码配置上下文... 第7节。公共类MyContext:DbContext {受保护的重写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

我发现我必须在dotnet核心上使用ModelBuilder而不是DbModelBuilder。
kiml42

6

我以为我会补充这个问题,因为它是排名靠前的Google搜索结果。

正如注释中所指出的那样,在EF Core中,不支持使用注释(键属性),并且必须使用流利的注释。

当我在进行从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);
}

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.