EF Core, работающий с альтернативными первичными ключами - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть несколько моделей EF Core, построенных с использованием dotnet ef dbContext scaffold для производства моделей с использованием подхода, основанного на базе данных.Моя проблема заключается в том, что база данных использует целочисленный первичный ключ, используемый для связывания таблиц, но имеет строковый индекс, который будет использоваться в качестве нормального индекса для поиска в таблице.

Однако: при попытке использовать FindAsync("abc000") Я получаю совершенно ожидаемую ошибку The key value at position 0 of the call to 'DbSet<Entity>.Find' was of type 'string', which does not match the property type of 'long'.

Итак, два вопроса:

  1. Как EF выяснил, каким был первичный ключ?
  2. Есть ли какой-нибудькак я могу перенастроить это, чтобы я мог использовать «Найти» для поиска сущностей по имени, но сохранить первичные ключи автоинкремента?
  3. Я глуп, что предпочитаю целочисленные ключи с автоинкрементом в качестве полей для объединения таблицon?

Они выглядят так:

class Entity
{
    long Id;
    string Key;
};

А в OnModelCreating:

modelBuilder.Entity<Entity>(entity =>
{
    entity.ToTable("tb_entity", "main");

     entity.HasIndex(e => e.Key)
           .HasName("uq_entity_key")
           .IsUnique();

    entity.Property(e => e.Id).HasColumnName("_id");

    entity.Property(e => e.Key)
          .HasColumnName("key")
          .HasMaxLength(255);
}

SQL, который создал таблицы, выглядит следующим образом:

CREATE TABLE [tb_entity]
(
    _id BIGINT PRIMARY KEY IDENTITY(1,1),
    key NVARCHAR(255) CONSTRAINT uq_entity_key UNIQUE NOT NULL,
);

1 Ответ

0 голосов
/ 27 февраля 2019
  1. Как EF выяснил, что такое первичный ключ?

Если явно не указано с помощью атрибута [Key] или HasKey свободно API, это Convention :

По соглашению, свойство с именем Id или <type name>Id будет настроено как ключ сущности.

Youможно увидеть эту информацию, изучив

var pk = context.Model.FindEntityType(typeof(Entity)).FindPrimaryKey();
Можно ли как-то перенастроить это, чтобы я мог использовать «Найти» для поиска сущностей по имени, но сохранить первичные ключи автоинкремента?

Вы можете лгать EFЯдро использует аннотации данных / свободный API, что PK для Entity равно Name, но я не рекомендую это, потому что это приведет к неправильным предположениям для отношений FK, и в целом это плохо.

Вместо этого просто не используйте методы Find / FindAsync, которые предназначены для ПК.First, FirstOrDefault, Single и SingleOrDefault (и их Async аналоги) позволяют выполнять поиск по любым критериям, например, вместо FindAsync("abc000") вы будете использовать FirstOrDefaultAsync(e => e.Name == "abc000").

.Единственное отличие состоит в том, что Find методы сначала выполняют поиск в локальном кэше, что не имеет большого преимущества в большинстве сценариев использования.С другой стороны, методы Find не поддерживают активную загрузку, в то время как последние поддерживают.Последние выполняются для базы данных, и поскольку для этого столбца существует уникальный индекс, они должны быть достаточно производительными.

Глупо ли я предпочитаю целочисленные ключи с автоинкрементом в качестве полей для объединения таблиц?

Это довольно стандартный дизайн БД и, как правило, предпочтительнее, чем естественные PK, я неЯ не вижу никаких проблем с этим.

...