Можно ли использовать сложные типы в качестве первичных ключей в 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
.
Таким образом, когда в качестве первичного ключа необходимо определить 4 свойства, это затрудняет вычисление и хранение информации. Я пробовал раньше. Есть ли решение этой проблемы, о котором я не знаю?
Самый простой способ — использовать наследование 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});
})
Затем обновите базу данных с помощью измененного составного ключа.
Вы также можете настроить несколько свойств в качестве ключа сущности — это называется составным ключом. Соглашения устанавливают составной ключ только в определенных случаях — например, для коллекции принадлежащих типов. Пример: [PrimaryKey(nameof(State), nameof(LicensePlate))]