Как определить составной первичный ключ для существующей таблицы базы данных?

Я работаю над проектом Core MVC, который считывает данные (не требуется запись) из уже существующей базы данных. К сожалению, в этой базе полный бардак, но я ничего не могу в ней изменить (а даже если бы и мог, то не стал бы трогать ее и 10-футовым шестом).

Некоторые из актуальных проблем базы данных следующие:

  • Таблицы не имеют отношения внешнего ключа друг к другу и содержат данные, которые лучше всего вводить в подтаблицу; тот, кто создал базу данных, похоже, использовал таблицы, как если бы они были электронными таблицами Excel.
  • Первичные или внешние ключи не определены.
  • Имена таблиц и столбцов кажутся инициалами содержащихся данных (для воображаемого примера таблица, которую обычно называют «Клиент», вместо этого будет называться «dbbc» для «База данных — бизнес-клиент»).
  • Таблицы не находятся в схеме "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] к обоим столбцам, которые составляют воображаемый составной первичный ключ.
  • Я добавил значение в свойство Order атрибута [Column], так как прочитал, что оно требуется для составных ключей.
  • Я сопоставил только те столбцы, которые мне нужно использовать, поскольку в таблице примерно в 10 раз больше столбцов, чем нужно для этого проекта.

Тем не менее, попытка запустить проект выдает ошибку:

InvalidOperationException: Тип сущности «MyProject.Models.Order» требует определения первичного ключа.

Есть ли что-нибудь еще, что я могу добавить, чтобы эта таблица работала с Entity Framework?

EDIT: я обнаружил, что это работает, если я определяю его в методе OnModelCreating контекста, например modelBuilder.Entity<Order>().HasKey(ord => new { ord.OrderNo, ord.OrderLineNo });. Однако я бы предпочел делать это только с атрибутами, если это возможно.




Ответы (1)


Ваша конфигурация отлично работает с EF6. Но вы должны быть осторожны при использовании аннотаций данных с EF Core (похоже, Fluent API будет предпочтительным подходом).

В разделе документации Keys(primary) прямо указано:

Вы также можете использовать Fluent API, чтобы настроить несколько свойств в качестве ключа объекта (известного как составной ключ). Составные ключи можно настроить только с помощью Fluent API — соглашения никогда не установят составной ключ, и вы не сможете использовать аннотации к данным для его настройки.

Итак, вам действительно нужно использовать:

modelBuilder.Entity<Order>().HasKey(e => new { e.OrderNo, e.OrderLineNo });
person Ivan Stoev    schedule 03.10.2016
comment
Как сделать один из этих столбцов DESC (по убыванию) упорядоченным? Как конечно можно сделать в SQL? - person Nicholas Petersen; 21.05.2018
comment
@NicholasPetersen Боюсь, все, что вы можете сделать в EF Core, — это указать имя PK и для SqlServer, создавать ли кластеризованный или некластеризованный индекс. Для других индексов вы также можете указать фильтр. Но это все, так что ответ - нет. В SQL AFAIK вы можете это сделать - по крайней мере, для SqlServer. - person Ivan Stoev; 21.05.2018
comment
спасибо Иван. Мужик, это облом. Я широко использую составные PK, и для некоторых из них важен порядок DESC, например, когда вы хотите, чтобы естественный порядок поиска был самым последним. - person Nicholas Petersen; 21.05.2018
comment
@NicholasPetersen Итак, вы полагаетесь на миграцию EF Core? Вы всегда можете изменить сгенерированный код миграции и добавить migrationBuilder.Sql("...") после вызова CreateTable. Внутри sql вы можете удалить ПК и воссоздать его с нужными параметрами. - person Ivan Stoev; 21.05.2018