我认为不打算修改ef core csharp代码生成。但是要生成自定义迁移语句(在我的情况下是触发器),我按照以下步骤执行(仅缩短到相关部分),使用SqlOperation。
实现一个ModelDiffer。
public class MyMigrationsModelDiffer : MigrationsModelDiffer {
public MyMigrationsModelDiffer(IRelationalTypeMappingSource typeMappingSource,
IMigrationsAnnotationProvider migrationsAnnotations,
IChangeDetector changeDetector,
IUpdateAdapterFactory updateAdapterFactory,
CommandBatchPreparerDependencies commandBatchPreparerDependencies)
: base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies) { }
protected override IEnumerable<MigrationOperation> Diff(IModel source, IModel target, DiffContext diffContext) {
return base.Diff(source, target, diffContext).Concat(GetTriggerTriggerDifferences(source, target));
}
public override Boolean HasDifferences(IModel source, IModel target) {
return base.HasDifferences(source, target) || HasTriggerAnnotationDifferences(source, target);
}
public IEnumerable<MigrationOperation> GetTriggerTriggerDifferences(IModel source, IModel target) {
if (source == null || target == null) {
return new new List<MigrationOperation>(0);
}
Dictionary<String, IAnnotation> triggerAnnotationPerEntity = new Dictionary<String, IAnnotation>();
foreach (var entityType in source.GetEntityTypes()) {
triggerAnnotationPerEntity[entityType.Name] = GetTableAnnotation(entityType);
}
var operations = new List<MigrationOperation>();
foreach (var entityType in target.GetEntityTypes()) {
triggerAnnotationPerEntity.TryGetValue(entityType.Name, out IAnnotation sourceTriggerTable);
IAnnotation targetTriggerTable = GetTableAnnotation(entityType);
if (targetTriggerTable?.Value == sourceTriggerTable?.Value) {
continue;
}
Boolean isCreate = targetTriggerTable != null;
String tableName = (entityType as EntityType)?.GetTableName();
String primaryKey = entityType.FindPrimaryKey().Properties[0].Name;
if (isCreate) {
SqlOperation sqlOperation = new SqlOperation();
sqlOperation.Sql = $@"CREATE TRIGGER...";
operations.Add(sqlOperation);
}
else {
}
}
return operations;
}
private static IAnnotation GetTableAnnotation(IEntityType entityType) {
return entityType.GetAnnotations()?.FirstOrDefault(x => x.Name == "WantTrigger");
}
public Boolean HasTriggerAnnotationDifferences(IModel source, IModel target) {
return GetTriggerTriggerDifferences(source, target).Any();
}
}
在您的DbContext中替换模型差异
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
base.OnConfiguring(optionsBuilder);
if (optionsBuilder == null) {
return;
}
optionsBuilder.ReplaceService<IMigrationsModelDiffer, MyMigrationsModelDiffer>();
}
使用注解来标记所需的模型。
builder.Entity<MyTable>().HasAnnotation("WantTrigger", "1.0");
MyDesignTimeServices
,EF Core工具会使用反射自动发现它。我发布的示例代码已经完整,可以直接运行。它不需要在任何地方注册MyDesignTimeServices
。有关更多信息,请参见设计时服务。这适用于所有命令行工具(在_设计时_)。如果您想在_运行时_应用迁移,则需要在DI容器中注册ICSharpMigrationOperationGenerator
(并且根本不需要IDesignTimeServices
实现)。 - lauxjpnConfigureDesignTimeServices
,旨在通过dotnet ef
从控制台运行。 它还明确解决了OP想要解决问题的方式。 话虽如此,我确实概述了另一种迁移操作的正确实现方式,在如何正确实现其他MigrationOperation(例如触发器创建)
中。 如果有人需要实际的代码,我很乐意提供一些。 - lauxjpndotnet ef migrations add "SomeMigration"
命令?运行命令时是否有任何错误消息?关于描述正在发生的事情:这都是非常高级的东西。给出一份充分的解释并说明其工作原理需要太多时间。如果您有具体问题,请随时提问。否则,请查看 EF Core 源代码或文档(例如关于IDesignTimeServices
)。 - lauxjpn