Ключи

Ключ служит уникальным идентификатором для каждого экземпляра сущности. Большинство сущностей в EF имеют один ключ, который сопоставляется с понятием первичного ключа в реляционных базах данных (для сущностей без ключей см . раздел "Без ключей"). Сущности могут иметь дополнительные ключи за пределами первичного ключа (дополнительные сведения см. в разделе "Альтернативные ключи ").

Настройка первичного ключа

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

internal class Car
{
    public string Id { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}

internal class Truck
{
    public string TruckId { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}

Примечание.

Типы сущностей, принадлежащие типы сущностей, используют разные правила для определения ключей.

Вы можете настроить одно свойство в качестве первичного ключа сущности следующим образом:

internal class Car
{
    [Key]
    public string LicensePlate { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}

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

Примечание.

Атрибут [PrimaryKey] появился в EF Core 7.0. Используйте API Fluent в более ранних версиях.

[PrimaryKey(nameof(State), nameof(LicensePlate))]
internal class Car
{
    public string State { get; set; }
    public string LicensePlate { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}

Создание ценностей

Для не составных числовых и первичных ключей GUID EF Core настраивает для вас создание значений по соглашению. Например, числовой первичный ключ в SQL Server автоматически настраивается как столбец IDENTITY. Дополнительные сведения см . в документации по генерации значений и рекомендациям по конкретным стратегиям сопоставления наследования.

Имя первичного ключа

По соглашению для первичных ключей реляционных баз данных создаются с именем PK_<type name>. Имя ограничения первичного ключа можно настроить следующим образом:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasKey(b => b.BlogId)
        .HasName("PrimaryKey_BlogId");
}

Ключевые типы и значения

Хотя EF Core поддерживает использование свойств любого примитивного типа в качестве первичного ключа, включая stringGuidи byte[] другие, не все базы данных поддерживают все типы в качестве ключей. В некоторых случаях значения ключей можно преобразовать в поддерживаемый тип автоматически, в противном случае преобразование должно быть указано вручную.

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

Важно!

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

Альтернативные ключи

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

Совет

Если вы просто хотите применить уникальность в столбце, определите уникальный индекс, а не альтернативный ключ (см . индексы). В EF альтернативные ключи доступны только для чтения и предоставляют дополнительную семантику по уникальным индексам, так как они могут использоваться в качестве целевого объекта внешнего ключа.

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

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogUrl)
            .HasPrincipalKey(b => b.Url);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public string BlogUrl { get; set; }
    public Blog Blog { get; set; }
}

Можно также настроить одно свойство в качестве альтернативного ключа:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Car>()
        .HasAlternateKey(c => c.LicensePlate);
}

Можно также настроить несколько свойств в качестве альтернативного ключа (известного как составной альтернативный ключ):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Car>()
        .HasAlternateKey(c => new { c.State, c.LicensePlate });
}

Наконец, по соглашению индекс и ограничение, введенные для альтернативного ключа, будут названы AK_<type name>_<property name> (для составных альтернативных ключей <property name> становится разделенный подчеркиванием список имен свойств). Можно настроить имя индекса альтернативного ключа и уникального ограничения:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Car>()
        .HasAlternateKey(c => c.LicensePlate)
        .HasName("AlternateKey_LicensePlate");
}