2013-08-26 6 views
2

У меня есть модель POCO, для которой свойство первичного ключа отображается на столбец с другим именем.Entity Framework Migrations: PrimaryKey

модель что-то вроде:

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' does не существует в целевой таблице или представлении.

Кажется, что при создании sql-кода свойство name строителя столбцов не используется. Вариант -verbose при миграции дает мне этот код:

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

Любые идеи? Является ли это очевидной ошибкой?

+0

FWIW, такая же ошибка существует для ForeignKey и Index на TableBuilder. –

ответ

2

Для того чтобы сообщить Entity Framework имя столбца для SQL запросов, которые EF сгенерирует вам необходимо указать его для модели, а не в миграции, либо с аннотациями данных ...

[Column("intTransactionID")] 
public long Id { get; set; } 

.. .Или с Fluent API:

modelBuilder.Entity<Transaction>() 
    .Property(t => t.Id) 
    .HasColumnName("intTransactionID"); 

После того, как вы определили имя столбца таким образом, вам не нужно определить его в коде миграции больше.

Параметр name в используемом вами классе миграции влияет на сценарий DDL, который отправляется в базу данных, но не указывает метаданные модели EF, что столбец имеет другое имя.

Честно говоря, я не знаю ни одного варианта использования параметра name в Миграционном коде.

Редактировать

Я проверил, что он работает на следующем примере:

  • Я использую свой класс:

    public class Transaction 
    { 
        public long Id { get; set; } 
    } 
    
  • И этот контекст, в котором я определить название столбца с Fluent API:

    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"); 
        } 
    } 
    
  • Затем я запустил enable-migrations и add-migration InitialSchema на консоли диспетчера пакетов.

  • Я получаю этот DbMigration класс, то:

    public partial class InitialSchema : DbMigration 
    { 
        public override void Up() 
        { 
         CreateTable(
          "dbo.dtlTransactions", 
          c => new 
           { 
            intTransactionID = c.Long(nullable: false, identity: true), 
           }) 
          .PrimaryKey(t => t.intTransactionID); 
        } 
    
        public override void Down() 
        { 
         DropTable("dbo.dtlTransactions"); 
        } 
    } 
    
  • Тогда я называю update-database -script на консоли менеджера пакетов и получить этот DDL-скрипт для таблицы - что является правильным и ожидаемым сценарием:

    CREATE TABLE [dbo].[dtlTransactions] (
        [intTransactionID] [bigint] NOT NULL IDENTITY, 
        CONSTRAINT [PK_dbo.dtlTransactions] PRIMARY KEY ([intTransactionID]) 
    ) 
    
+0

К сожалению, это означает, что моя модель больше не POCO. Мне не нравится добавлять эти атрибуты в мою модель, поскольку она тесно связывает ее с EF. Кроме того, параметр name не влияет на скрипт DDL вообще, как видно из моего сообщения. –

+0

О, я фактически использую API Fluent для отображения моих объектов. Отображение здесь не является проблемой. Это DDL, который генерируется неправильно. –

+0

@ErnstKuschke: DDL по-прежнему ошибочен, если вы удалили идентификатор «name:» intTransactionID »из кода миграции? – Slauma

0

Похоже, что это действительно ошибка в API EF Migrations API, подтвержденная здесь:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/3868f5e7-144a-4212-9eb7-80a3b1e32fc2/entity-framework-migrations-primarykey#3868f5e7-144a-4212-9eb7-80a3b1e32fc2

+1

Парень, который ответил там, не является членом команды разработчиков EF, и я не буду рассматривать то, что он пишет, как «подтверждение», скорее как мнение. Более того, он предлагает такое же решение, как и я. Я бы не назвал это «обходным путем», потому что отображение в метаданных модели (с аннотациями или Fluent API) имеет важное значение, так что EF может создавать операторы SQL с правильными именами столбцов. Вы не можете определить это сопоставление с помощью Migrations, и это не его цель. Целью является обновление схемы базы данных, и миграция не знает, как сопоставить эту схему с классами модели. – Slauma

+0

@Slauma, похоже, вы не понимаете проблему. Решение, которое он или вы предлагали, не было решением. Мои классы * отображаются на карту, как вы оба предложили. Ошибка отображается * not * в сопоставлении, но в Migrations, которые игнорируют любое настраиваемое имя, вы указываете столбцы. Это делает Migrations бесполезным в EF. –

+0

Скажите, у вас есть класс и добавьте к нему свойство 'Remark', и вы вызываете' .HasColumnName («X») 'с Fluent API, потому что хотите, чтобы столбец в таблице был назван« X »вместо' Remark' , Вы делаете это, потому что, когда вы запускаете запрос с 'Where (a => a.Remark ==" SomeText ")' вы указываете EF, что он должен быть переведен в SQL 'WHERE X = N'SomeText'' (примечание: * * X **, а не ** Замечание **). Затем вы вызываете «add-migration» и создается миграция, которая добавляет столбец «X» к таблице (** не «Замечание» **). ** Почему вы хотите переименовать этот столбец в этом классе миграции в «Y»? ** – Slauma

0

Я тестировал, используя оба параметра отображения (свободно и атрибуты). В обоих случаях при создании миграции с использованием Add-Migration любые пользовательские сопоставления полностью игнорируются.

Отображения работают, но миграций нет. Это означает, что миграция не используется при использовании 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().

+0

«* Я тестировал, используя оба параметра сопоставления (свободно и атрибуты). В обоих случаях при создании миграции с использованием Add-Migration любые пользовательские сопоставления полностью игнорируются. *« Другими словами, вы сделали то же самое, что и в Измените раздел в моем ответе, и вы не получите результат, который у меня был? Ну, это то, что вы можете * действительно * сообщить как ошибку, если вы можете предоставить воспроизводимый образец. – Slauma

Смежные вопросы