Как трябва да дефинирам съставен първичен ключ за съществуваща таблица на база данни?

Работя върху проект 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?

РЕДАКТИРАНЕ: Открих, че работи, ако го дефинирам в метода 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 можете да пуснете PK и да го създадете отново с желаните опции. - person Ivan Stoev; 21.05.2018