You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:35:12