Мои правила именования следующие:
- Первичный ключ (PK): pk_TABLE_NAME
- Внешний ключ (ФК): fk_PARENT_CHILD_JOINED_COLUMNS
PARENT: ссылающаяся таблица (дочерняя) - CHILD: ссылочная таблица (родительская)
- JOINED_COLUMNS: короткое объединение имен объединенных столбцов.
- Если столбцов несколько, объедините их имена.
- Если индекс уникален, имя должно начинаться с ux_
Мягкое удаление / Активный Флаг:
- is_active: все таблицы имеют столбец is_active со значением по умолчанию 1.
- Этот столбец указывает, является ли строка активной (1) или логически удаленной (0).
Возможно ли это в EF Core? Как я могу эффективно реализовать такое решение?
Что я пробовал
Я написал собственное расширение EF Core для автоматического применения пользовательских соглашений об именах для PK, FK, индексов и других правил.
Чего я ожидал
Во время миграции имена PK, FK и индексы будут автоматически генерироваться в соответствии с правилами с правильным использованием имен таблиц и столбцов.
Что произошло на самом деле
- Имена индексов использовали имена классов сущностей вместо фактических имен таблиц.
- Различия в регистре (верхний/нижний) приводили к добавлению дополнительных имен таблиц к каждому миграция.
public static class ModelBuilderExtensions
{
public static void ApplyConventions(this ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
var tableName = entity.GetTableName().ToLowerInvariant();
// 1. PK
var pk = entity.FindPrimaryKey();
if (pk != null)
{
pk.SetName($"pk_{tableName}");
}
// 2. FK
foreach (var fk in entity.GetForeignKeys())
{
var fkName = $"fk_{tableName}_{fk.PrincipalEntityType.GetTableName().ToLowerInvariant()}_{string.Join("_", fk.Properties.Select(p => p.GetColumnName().ToLowerInvariant()))}";
fk.SetConstraintName(fkName);
fk.DeleteBehavior = DeleteBehavior.Restrict;
}
// 3. Index (idx / ux)
foreach (var index in entity.GetIndexes())
{
var prefix = index.IsUnique ? "ux" : "idx";
var indexName = $"{prefix}_{tableName}_{string.Join("_", index.Properties.Select(p => p.GetColumnName().ToLowerInvariant()))}";
index.SetDatabaseName(indexName);
}
// 4. is_active default true
var isActiveProp = entity.FindProperty("IsActive");
if (isActiveProp != null)
{
isActiveProp.SetDefaultValue(true);
}
}
}
}
AppDbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
// ModelBuilderExtensions (PK, FK, Index, Comment, Cascade)
modelBuilder.ApplyConventions();
base.OnModelCreating(modelBuilder);
}
Пример результатов миграции:
migrationBuilder.CreateIndex(
name: "idx_Order_OrderId",
table: "Order",
column: "OrderId");
Но я ожидал:
migrationBuilder.CreateIndex(
name: "idx_orders_order_id",
table: "orders",
column: "order_id");
Подробнее здесь: https://stackoverflow.com/questions/797 ... ndex-seque
Мобильная версия