具有列序号<>的实体框架组合键定义主键序数

时间:2015-09-14 11:45:23

标签: entity-framework ef-code-first primary-key code-first

给出一个表格

CREATE TABLE pk_ordinal_test
(
 C1 INT NOT NULL,
 C2 INT NOT NULL,
 C3 INT NOT NULL
)
ALTER TABLE pk_ordinal_test ADD PRIMARY KEY (C3, C1);

请注意,主键已定义为C3,C1,列顺序为C1,C3。

主键的实体框架代码优先配置是否应在主键序号中:

HasKey(x => new { x.C3, x.C1 });

或应该在列序号

HasKey(x => new { x.C1, x.C3 });

在MSI安装中使用EF Tools v6.1.3,使用Visual Studio - >添加 - >新项目 - > ADO.Net实体数据模型。选择Code-first,生成以下内容:

public partial class pk_ordinal_test
{
    [Key]
    [Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int C1 { get; set; }

    public int C2 { get; set; }

    [Key]
    [Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int C3 { get; set; }
}

上面定义的主要列顺序不正确。

3 个答案:

答案 0 :(得分:2)

如果您的实体具有复合外键,则必须指定用于相应主键属性的相同列顺序,因此您必须选择的选项是主键序号:

HasKey(x => new { x.C3, x.C1 });

答案 1 :(得分:1)

EF doesn't care about the order in the database. It always refers to columns by name, not ordinal. The thing that does matter is what octavioccl mentioned above--the order needs to be consistent across your EF model. If a primary key is specified one way, foreign keys that refer to that primary key must be in the same order.

I wrote the Code-first generator. There was a "bug" in the component that extracts information from the database. Like you found, it strips out column order in composite keys. It does, however, preserve which column in a foreign key map to which column in the primary key. So, even though it may not reflect what the layout is in the database, the generated model will work correctly with your database.

答案 2 :(得分:0)

如果在Visual Studio 2015中从数据库生成代码优先模型,它将按照模式中列的顺序为键分配Order属性。因此,如果执行LINQ查询(例如“查找”,则需要按“列顺序”对主键进行排序,因为按键按架构列顺序排序。

如果您在EDMX中使用Database First方法,则指导也是使用设计器中每列顺序的主键顺序。因此,如果C1在C3之前出现并且都是主键,则find方法将用作Find(C1,C3)。

因此,有两项证据表明,在使用复合键指定主键顺序时,您将在代码或设计器中生成模型时使用列顺序,因为代码生成器将使用列顺序来命令钥匙。

OP的示例(由于我在VS扩展中的查询而生成)有点不同,因为模式正在生成主键排序。所以让我们退一步看看这个“嘿,我将从你的模式生成一个代码第一个模型。我看到C1和C3是主键。当我从你的模式生成代码第一个模型时我会去按顺序迭代列并为主键列分配Order属性。“这会直接导致基于列顺序的使用模式。

再次,OP正在从模式生成模型,EF按照模式/列顺序生成代码中的顺序。

SET ANSI_NULLS ON
GO 

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[UserSetting](
    [userId] [INT] NOT NULL,
    [deleted] [BIT] NULL CONSTRAINT [DF_UserSetting_deleted]  DEFAULT ((0)),
    [key] [NVARCHAR](MAX) NULL,
    [lastUpdatedUtc] [DATETIME2](7) NULL CONSTRAINT [DF_UserSetting_lastUpdatedUtc]  DEFAULT (GETUTCDATE()),
    [notificationMessage] [NVARCHAR](MAX) NULL,
    [notificationType] [INT] NULL,
    [stringValue] [NVARCHAR](MAX) NULL,
    [synced] [BIT] NULL,
    [userSettingId] [NCHAR](36) NOT NULL,
    [timestamp] [DATETIME2](7) NULL CONSTRAINT [DF_UserSetting_timestamp]  DEFAULT (GETUTCDATE()),
    [modelVersion] [INT] NULL CONSTRAINT [DF_UserSetting_modelVersion]  DEFAULT ((0)),
    [preview] [BIT] NULL,
    [createdUtc] [DATETIME2](7) NULL CONSTRAINT [DF_UserSetting_createdUtc]  DEFAULT (GETUTCDATE()),
 CONSTRAINT [PK_UserSetting] PRIMARY KEY CLUSTERED 
(
    [userSettingId] ASC,
    [userId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

以下是Visual Studio Code First中从数据库中生成的内容:

[Table("UserSetting")]
    public partial class UserSetting
    {
        [Key]
        [Column(Order = 0)]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int userId { get; set; }

        public bool? deleted { get; set; }

        public string key { get; set; }

        [Column(TypeName = "datetime2")]
        public DateTime? lastUpdatedUtc { get; set; }

        public string notificationMessage { get; set; }

        public int? notificationType { get; set; }

        public string stringValue { get; set; }

        public bool? synced { get; set; }

        [Key]
        [Column(Order = 1)]
        [StringLength(36)]
        public string userSettingId { get; set; }

        [Column(TypeName = "datetime2")]
        public DateTime? timestamp { get; set; }

        public int? modelVersion { get; set; }

        public bool? preview { get; set; }

        [Column(TypeName = "datetime2")]
        public DateTime? createdUtc { get; set; }
    }