Как установить ComplexTypes в качестве первичного ключа в EF Core

Можно ли использовать сложные типы в качестве первичных ключей в EF Core 8?

У меня есть сложный тип, свойства которого должны быть уникальными и рассматриваться как первичный ключ.

[ComplexType]
public class ContractID
{
    public readonly short BranchCode;
    public readonly short TypeCode;
    public readonly int CIF;
    public readonly int Counter;

    public ContractID(short branchCode, short typeCode, int cIF, int counter)
    {
        BranchCode = branchCode;
        TypeCode = typeCode;
        CIF = cIF;
        Counter = counter;
    }
}

И у меня есть сущность, первичным ключом которой является указанный выше сложный тип:

public class Contract 
{
    public ContractID ID { get; set; }
    public long ApprovedAmount { get; set; }
    public long Amount { get; set; }
    public short Duration { get; set; }
    public byte Rate { get; set; } 
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

public class ContractConfiguration : IEntityTypeConfiguration<Contract>
{
    public void Configure(EntityTypeBuilder<Contract> builder)
    {
        builder.ToTable("Contracts");        
        builder.HasKey(x => x.ID);
        builder.ComplexProperty(x => x.ID);
        builder.Property(x => x.ID).ValueGeneratedNever();  
        builder.Property(x => x.StartDate).HasColumnType("datetime2");
        builder.Property(x => x.EndDate).HasColumnType("datetime2");
    }
}

Но при запуске команды миграции

Add-Migration Init -Context AssistantDBContext

Я получаю следующую ошибку:

Невозможно создать «DbContext» типа «AssistantDBContext». Исключение «Идентификатор свойства или навигации» невозможно добавить к типу «Контракт», поскольку свойство или навигация с таким же именем уже существует в типе «Контракт». был выброшен при попытке создать экземпляр. Информацию о различных шаблонах, поддерживаемых во время разработки, см. https://go.microsoft.com/fwlink/?linkid=851728

Ссылка в конце сообщения мне тоже не помогла. В чем смысл ошибки? Есть ли решение и возможно ли такое в принципе?

Я ожидал, что проблема будет решена путем определения сложного типа в OnModelCreating.

Вы также можете настроить несколько свойств в качестве ключа сущности — это называется составным ключом. Соглашения устанавливают составной ключ только в определенных случаях — например, для коллекции принадлежащих типов. Пример: [PrimaryKey(nameof(State), nameof(LicensePlate))]

D A 02.09.2024 11:27

Таким образом, когда в качестве первичного ключа необходимо определить 4 свойства, это затрудняет вычисление и хранение информации. Я пробовал раньше. Есть ли решение этой проблемы, о котором я не знаю?

ROMO 02.09.2024 13:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Самый простой способ — использовать наследование Contract: ContractID вместо complexType.
Если это не соответствует вашим требованиям, вы можете попробовать отредактировать файл миграции.
Добавить пустой конструктор в ContractID

        [ComplexType]
        public class ContractID
        {
            public ContractID(){}

            public ContractID(short branchCode, short typeCode, int cIF, int counter)
            {
               ...
            }
        }

Измените имя столбца сложного свойства. Установите «сумму» в качестве ключа.

    public class ContractConfiguration : IEntityTypeConfiguration<Contract>
    {
        public void Configure(EntityTypeBuilder<Contract> builder)
        {
            builder.ToTable("Contracts");
            builder.Property(x => x.StartDate).HasColumnType("datetime2");
            builder.Property(x => x.EndDate).HasColumnType("datetime2");

            builder.OwnsOne(x => x.ID, p =>
            {
                p.Property(y => y.BranchCode).HasColumnName("BranchCode");
                p.Property(y => y.TypeCode).HasColumnName("TypeCode");
                p.Property(y => y.CIF).HasColumnName("CIF");
                p.Property(y => y.Counter).HasColumnName("Counter");
            });

            //set "Amount" as primary key temporary to modify later
            builder.Property(x => x.Amount).ValueGeneratedNever();
            builder.HasKey(x => x.Amount);
        }
    }

После add-migration откройте файл миграции и проверьте метод Up. Найдите следующий код
Замените ключ составным ключом.

constraints: table =>
{
    table.PrimaryKey("PK_Contracts", x => new {x.BranchCode,x.TypeCode,x.CIF,x.Counter});
})

Затем обновите базу данных с помощью измененного составного ключа.

Другие вопросы по теме