如何为现有的数据库表定义一个复合主键?

3
我正在开发一个Core MVC项目,从一个预先存在的数据库中读取数据(无需写入)。不幸的是,这个数据库非常混乱,但我不能改变它的任何内容(即使我可以,我也不会去碰它)。
该数据库存在以下一些相关问题:
- 表之间没有任何外键关系,并且包含最好输入到子表中的数据;创建数据库的人似乎将表用作Excel电子表格。 - 没有定义主键或外键。 - 表和列的名称似乎是包含的数据的缩写(例如,通常称为“Customer”的表实际上被命名为“dbbc”,表示“Database - Business Customer”)。 - 表不在“dbo”模式中。
尽管如此,我被迫从这个数据库中读取数据,并且希望使用Entity Framework来完成。
该数据库托管在SQL Server 2008R2中。
我可以通过使用属性(例如[Table]、[Column]和[Key])使类具有正确的属性名称映射到实际列名称,从而在其中一个我必须使用的表上轻松实现它。然而,另一个表正在证明是一个问题。
这个表没有一个可以被视为主键的单独列,但我发现两个列的组合对于每一行都是唯一的,因此它们可以被视为复合主键(即使它们在数据库中没有被定义为这样)。
我定义了一个类如下(我更改了名称以隐藏此数据库的身份,尽管我很想指名道姓):
[Table("dbbo", Schema = "schema")]
public class Order
{
    [Key]
    [Column("order", Order = 0)]
    public string OrderNo { get; set; }

    [Key]
    [Column("order_line", Order = 1)]
    public string OrderLineNo { get; set; }

    [Column("qty")]
    public double Quantity { get; set; }

    [Column("pr")]
    public double Price { get; set; }
}
  • 我在构成虚拟复合主键的两个列上都添加了 [Key] 属性。
  • 我在 [Column] 属性的 Order 属性中添加了一个值,因为我读到它对于复合键是必需的。
  • 我只映射了需要使用的列,因为该表的列比与此项目相关的列多10倍左右。

然而,尝试运行该项目会产生错误:

InvalidOperationException: 实体类型 'MyProject.Models.Order' 要求定义主键。

是否还有其他内容可以添加使该表与 Entity Framework 协同工作?

编辑:我发现如果在上下文的 OnModelCreating 方法中定义它,如 modelBuilder.Entity<Order>().HasKey(ord => new { ord.OrderNo, ord.OrderLineNo });,则它可以正常工作。但是,如果可能的话,我仍然更喜欢仅使用属性来完成它。

1个回答

11
您的配置在EF6中运行良好。但是,在使用Data Annotations和EF Core时必须小心(似乎Fluent API将成为首选方法)。文档的Keys(primary)部分明确说明:
“您还可以使用Fluent API来配置多个属性作为实体的键(称为复合键)。只能使用Fluent API配置复合键 - 约定永远不会设置复合键,也不能使用Data Annotations来配置复合键。”
因此,您确实需要使用:
modelBuilder.Entity<Order>().HasKey(e => new { e.OrderNo, e.OrderLineNo });

你如何使其中一列按照DESC(降序)排序?就像在SQL中一样? - Nicholas Petersen
1
@NicholasPetersen,恐怕在EF Core中,你只能指定PK名称以及对于SqlServer是创建聚集索引还是非聚集索引。对于其他索引,你也可以指定过滤器。但这就是全部了,所以答案是否定的。在SQL中,据我所知,你可以这样做——至少对于SqlServer来说是可以的。 - Ivan Stoev
谢谢Ivan。哎呀,真是个糟糕的事情。我广泛使用复合主键,并且在其中一些情况下,按降序排列非常重要,比如当你希望自然检索顺序是最近的时候。 - Nicholas Petersen
@NicholasPetersen 所以你依赖于EF Core迁移?你可以随时修改生成的迁移代码,在CreateTable调用之后添加migrationBuilder.Sql("...")。在sql内部,您可以删除PK并使用所需选项重新创建它。 - Ivan Stoev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接