.net 实体框架迁移:PrimaryKey

.net 实体框架迁移:PrimaryKey,.net,entity-framework,entity-framework-migrations,.net,Entity Framework,Entity Framework Migrations,我有一个POCO模型,其主键属性映射到具有不同名称的列上 该模型类似于: public class Transaction { public long Id { get; set; } //....more props } CreateTable( "dbo.dtlTransactions", c => new { Id = c.Long(nullable: false, identity: true, name:

我有一个POCO模型,其主键属性映射到具有不同名称的列上

该模型类似于:

public class Transaction
{
    public long Id { get; set; }
    //....more props
}
CreateTable(
    "dbo.dtlTransactions",
    c => new
        {
            Id = c.Long(nullable: false, identity: true, name: "intTransactionID"),
            //...more cols
        })
        .PrimaryKey(t => t.Id);
因此,迁移看起来像:

public class Transaction
{
    public long Id { get; set; }
    //....more props
}
CreateTable(
    "dbo.dtlTransactions",
    c => new
        {
            Id = c.Long(nullable: false, identity: true, name: "intTransactionID"),
            //...more cols
        })
        .PrimaryKey(t => t.Id);
但是,在运行迁移时,我得到:

System.Data.SqlClient.SqlException(0x80131904):列名“Id”不起作用 目标表或视图中不存在

在生成sql时,似乎没有使用columnbuilder的name属性。迁移中的-verbose选项提供了以下sql:

CREATE TABLE [dbo].[dtlTransactions] (
[intTransactionID] [bigint] NOT NULL IDENTITY,
--...other cols
CONSTRAINT [PK_dbo.dtlTransactions] PRIMARY KEY ([Id])

有什么想法吗?这是一个明显的错误吗?

为了告诉实体框架EF将生成的SQL查询的列名,您必须为模型指定列名,而不是在迁移中指定,或者使用数据注释

[Column("intTransactionID")]
public long Id { get; set; }
…或使用Fluent API:

modelBuilder.Entity<Transaction>()
    .Property(t => t.Id)
    .HasColumnName("intTransactionID");
public class MyContext : DbContext
{
    public DbSet<Transaction> Transactions { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Transaction>()
            .ToTable("dtlTransactions");

        modelBuilder.Entity<Transaction>()
            .Property(t => t.Id)
            .HasColumnName("intTransactionID");
    }
}
  • 在此上下文中,我使用Fluent API定义列名:

    modelBuilder.Entity<Transaction>()
        .Property(t => t.Id)
        .HasColumnName("intTransactionID");
    
    public class MyContext : DbContext
    {
        public DbSet<Transaction> Transactions { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Transaction>()
                .ToTable("dtlTransactions");
    
            modelBuilder.Entity<Transaction>()
                .Property(t => t.Id)
                .HasColumnName("intTransactionID");
        }
    }
    
  • 然后我在package manager控制台上调用
    update database-script
    ,并获取该表的DDL脚本,这是正确的和预期的脚本:

    创建表[dbo]。[dtlTransactions](
    [intTransactionID][bigint]不是空标识,
    约束[PK_dbo.dtlTransactions]主键([intTransactionID])
    )
    

  • 这似乎确实是EF Migrations API中的一个bug,正如这里确认的:


    我使用两种映射选项(fluent和attributes)进行了测试。在这两种情况下,当使用添加迁移生成迁移时,将完全忽略任何自定义映射

    映射可以工作,但迁移不能。这意味着当使用EF作为ORM时,迁移不可用

    一种解决方法是手工创建迁移,而不是使用TableBuilder,而是使用DbMigration方法:

    而不是

    CreateTable(
        "dbo.dtlTransactions",
        c => new
            {
                Id = c.Long(nullable: false, identity: true, name: "intTransactionID"),
                //...more cols
            })
            .PrimaryKey(t => t.Id, name: "intTransactionID");
    
    您可以使用:

    CreateTable(
        "dbo.dtlTransactions",
        c => new
            {
                Id = c.Long(nullable: false, identity: true, name: "intTransactionID"),
                //...more cols
            });
    AddPrimaryKey("dbo.dtlTransactions", "intTransactionId");
    

    TableBuilder.Index()也是如此-而不是使用CreateIndex()。

    FWIW,TableBuilder上的ForeignKey和Index似乎存在相同的错误。不幸的是,这样做意味着我的模型不再是POCO。我不喜欢将这些属性添加到我的模型中,因为它与EF紧密耦合。此外,name参数根本不会影响DDL脚本,正如我在文章中所看到的。哦,我实际上是在使用fluentapi映射实体。映射不是这里的问题。错误的是生成的DDL。@ErnstKuschke:如果从迁移代码中删除
    名称:“intTransactionID”
    ,DDL是否仍然错误?如果删除该名称,DDL不知道我希望将我的列命名为该名称。@ErnstKuschke:正如我在上面的回答中所说,您应该使用
    .HasColumnName来命名该列(“ItTraceNoID”;用Fluent API。这是我的答案。它应该生成正确的DDL,而不指定迁移代码中的列名。回答的人不是EF开发者团队的成员,我不认为他写的是“确认”。“,更像是一种观点。此外,他提出了与我相同的解决方案。我不会称之为“变通方法”,因为模型元数据中的映射(带有注释或Fluent API)是必不可少的,这样EF就可以创建具有正确列名的SQL语句。您不能用迁移定义此映射,这不是它的目的。其目的是更新数据库架构,而迁移不知道如何将此架构映射到模型类。@Slauma您似乎不理解这个问题。他或你提出的解决方案不是解决方案。正如你们两位所建议的,我的类被映射了。错误不在映射中,而是在迁移中,迁移会忽略您为列指定的任何自定义名称。这使得迁移在EF中毫无用处。例如,您有一个类,并向其中添加了一个属性
    Remark
    ,然后使用Fluent API调用
    .HasColumnName(“X”)
    ,因为您希望表中的列名为“X”,而不是
    Remark
    。这样做是因为当您使用
    Where(a=>a.Remark==“SomeText”)
    运行查询时,您告诉EF必须将其转换为SQL
    ,其中X=N'SomeText'
    (注意:X,不是Remark)。然后调用
    addmigration
    并创建一个迁移,该迁移将向表中添加一个名为“X”的列(而不是“备注”)。为什么要将此迁移类中的此列重命名为“Y”?即使这样做可行(使用
    name
    参数显然不完全可行),唯一的结果是使用
    Where(a=>a.Remark==“SomeText”)进行查询
    将不再工作,因为SQL查询仍然是
    ,其中X=N'SomeText'
    (因为
    “X”
    是模型元数据中的映射),但现在没有列“X”,而是“Y”。请记住,迁移只是打开SQLServerManagementStudio并手动向表中添加列“X”的方便替代。在映射中定义“X”后,您不会将此列称为“Y”。“我使用两个映射选项(fluent和attributes)进行了测试。在这两种情况下,使用添加迁移生成迁移时,所有自定义映射都会被完全忽略。”换句话说,你做的和我在我的答案中编辑部分做的完全一样,你没有得到我得到的结果???好吧,如果你能提供一个可复制的样本,这是一个真正可以报告为bug的东西。