IModel.GetRelationalModel未复制注解问题及替代方案咨询
问题:IModel转RelationalModel时注解丢失导致迁移差异比较异常
当通过以下两种方式将IModel转换为RelationalModel时:
- 使用
IModel.GetRelationalModel()扩展方法 - 使用接收
IModel的RelationalModel构造函数
原IModel中的注解未被保留,导致IMigrationsModelDiffer.GetDifferences()等函数无法按预期工作。事后手动复制注解也无济于事,因为GetDifferences()不会识别运行时注解。
是否存在可保留这些注解的RelationalModel创建方式?或者是否存在可使用运行时注解的GetDifferences()替代方法?
代码示例
var oldRelationalModel = oldModel.GetRelationalModel(); Log.Information("Old IModel Annotations: {0}", oldModel.GetAnnotations().Count()); Log.Information("Old RelationalModel Annotations: {0}", oldRelationalModel.GetAnnotations().Count()); var newRelationalModel = newModel.GetRelationalModel(); Log.Information("New IModel Annotations: {0}", newModel.GetAnnotations().Count()); Log.Information("New RelationalModel Annotations: {0}", newRelationalModel.GetAnnotations().Count());
日志输出
[15:57:46 INF] Old IModel Annotations: 5 [15:57:46 INF] Old RelationalModel Annotations: 0 [15:57:46 INF] New IModel Annotations: 5 [15:57:46 INF] New RelationalModel Annotations: 0
解决方案
1. 手动创建RelationalModel并保留注解
默认转换逻辑不会复制IModel上的注解,你可以手动创建RelationalModel后复制注解:
public static RelationalModel CreateRelationalModelWithAnnotations(IModel model) { var relationalModel = model.GetRelationalModel(); // 复制IModel上的注解到RelationalModel foreach (var annotation in model.GetAnnotations()) { if (!relationalModel.FindAnnotation(annotation.Name).Exists) { relationalModel.AddAnnotation(annotation.Name, annotation.Value); } } return relationalModel; }
注意:这种方式添加的是运行时注解,若要让IMigrationsModelDiffer识别,需确保注解是设计时可持久化注解(通过Annotate()方法添加)。
2. 自定义差异比较逻辑支持运行时注解
若无法修改RelationalModel创建方式,可扩展MigrationsModelDiffer来支持运行时注解的比较:
public class CustomMigrationsModelDiffer : MigrationsModelDiffer { public CustomMigrationsModelDiffer( IRelationalTypeMappingSource typeMappingSource, IMigrationsAnnotationProvider migrationsAnnotations, IChangeDetector changeDetector, IUpdateAdapterFactory updateAdapterFactory, CommandLoggerDependencies commandLoggerDependencies) : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandLoggerDependencies) { } protected override IEnumerable<AnnotationDifference> GetAnnotationDifferences( IAnnotatable source, IAnnotatable target, bool includeSharedAnnotations = true) { var defaultDifferences = base.GetAnnotationDifferences(source, target, includeSharedAnnotations).ToList(); // 补充运行时注解的差异对比 var sourceAnnotations = source.GetAnnotations(); var targetAnnotations = target.GetAnnotations(); // 查找源有但目标没有的注解 foreach (var sourceAnn in sourceAnnotations) { var targetAnn = targetAnnotations.FirstOrDefault(a => a.Name == sourceAnn.Name); if (targetAnn == null) { defaultDifferences.Add(new AnnotationDifference(sourceAnn.Name, sourceAnn.Value, null)); } else if (!Equals(sourceAnn.Value, targetAnn.Value)) { defaultDifferences.Add(new AnnotationDifference(sourceAnn.Name, sourceAnn.Value, targetAnn.Value)); } } // 查找目标有但源没有的注解 foreach (var targetAnn in targetAnnotations) { if (!sourceAnnotations.Any(a => a.Name == targetAnn.Name)) { defaultDifferences.Add(new AnnotationDifference(targetAnn.Name, null, targetAnn.Value)); } } return defaultDifferences; } }
然后在DI容器中替换默认实现:
services.AddScoped<IMigrationsModelDiffer, CustomMigrationsModelDiffer>();
3. 通过自定义注解提供者注册迁移注解
如果注解是用于迁移的自定义注解,推荐实现IMigrationsAnnotationProvider让EF Core自动识别:
public class CustomMigrationsAnnotationProvider : RelationalMigrationsAnnotationProvider { public CustomMigrationsAnnotationProvider(RelationalMigrationsAnnotationProviderDependencies dependencies) : base(dependencies) { } public override IEnumerable<IAnnotation> For(IAnnotatable annotatable) { var annotations = base.For(annotatable).ToList(); // 把自定义注解加入迁移识别集合 if (annotatable is IModel model) { var customAnn = model.FindAnnotation("YourCustomAnnotationName"); if (customAnn != null) { annotations.Add(customAnn); } } return annotations; } }
注册该提供者:
services.AddScoped<IMigrationsAnnotationProvider, CustomMigrationsAnnotationProvider>();
内容的提问来源于stack exchange,提问作者Hayden Browne
相关产品推荐
相关产品推荐

