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

使用Add-Migration时EdmFunction引发报错的问题排查

解决EF Code First注册自定义Edm函数导致Add-Migration报错的问题

你在EF Code First模式下注册自定义RemoveDiacritics Edm函数后,运行时功能正常,但执行add-migration test -verbose时抛出Sequence contains no elements异常,问题根源出在自定义约定类对迁移流程的干扰上。

问题原因拆解

当执行迁移命令时,EF需要生成并对比实体模型与数据库结构的映射关系,但你的RemoveDiacriticsFunctionConvention做了两个干扰迁移的操作:

  • 在Apply方法中手动调用了model.Compile(),提前编译了模型,导致后续迁移流程读取元数据时出现空序列异常;
  • 迁移流程本身不需要注册存储层的函数约定——迁移负责的是实体到数据库表结构的变更,自定义数据库函数需要单独处理,不需要参与模型对比。

分步解决方案

1. 让约定仅在运行时生效

修改ApplicationDBContext的OnModelCreating方法,添加判断逻辑,只在非迁移上下文时注册约定:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    
    // 仅在非迁移环境下注册自定义函数约定
    if (!IsRunningMigration())
    {
        modelBuilder.Conventions.Add(new RemoveDiacriticsFunctionConvention());
    }
}

// 辅助方法:判断当前是否处于迁移上下文
private bool IsRunningMigration()
{
    return AppDomain.CurrentDomain.GetAssemblies()
        .Any(assembly => assembly.FullName.StartsWith("EntityFramework.Migrations"));
}

2. 移除手动编译模型的代码

在RemoveDiacriticsFunctionConvention的Apply方法中,删掉model.Compile()这行代码——EF会自动处理模型编译,手动调用会打乱迁移的模型生成流程:

public void Apply(EntityContainer item, DbModel model)
{
    // 声明参数
    List<FunctionParameter> Parameters = new List<FunctionParameter>();
    Parameters.Add(FunctionParameter.Create("StringValue", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In));
    
    // 声明返回参数
    List<FunctionParameter> ReturnParameters = new List<FunctionParameter>();
    ReturnParameters.Add(FunctionParameter.Create("ReturnValue", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.ReturnValue));
    
    // 创建函数负载
    EdmFunctionPayload payload = new EdmFunctionPayload();
    payload.IsComposable = true;
    payload.Schema = "dbo";
    payload.StoreFunctionName = "RemoveDiacritics";
    payload.ReturnParameters = ReturnParameters;
    payload.Parameters = Parameters;
    
    // 创建并添加函数到模型
    EdmFunction function = EdmFunction.Create("RemoveDiacritics", "dbo", DataSpace.SSpace, payload, new MetadataProperty[] { });
    model.StoreModel.AddItem(function);
    
    // 移除这行手动编译代码
    // model.Compile();
}

3. 确保数据库中存在自定义函数

因为Code First迁移不会自动生成自定义函数的创建脚本,你需要手动处理:

  • 如果是首次迁移,在初始迁移的Up方法中添加创建函数的SQL:
public override void Up()
{
    // 其他迁移代码...
    Sql(@"
        CREATE FUNCTION dbo.RemoveDiacritics(@StringValue NVARCHAR(MAX))
        RETURNS NVARCHAR(MAX)
        AS
        BEGIN
            -- 替换为你的函数实现逻辑
            RETURN @StringValue;
        END
    ");
}
  • 如果数据库已存在该函数,可忽略此步骤。

为什么之前的尝试无效?

你添加的[NotMapped]和modelBuilder.Ignore<RemoveDiacriticsFunctionConvention>()是用来忽略实体类的映射,而RemoveDiacriticsFunctionConvention是约定类,不属于实体,所以这些配置对它完全不起作用。

内容的提问来源于stack exchange,提问作者KingOfBabu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:12:43