EF迁移报错GenerateCodeLiteral,应用运行正常但迁移失败
EF Core迁移报错:无法搭建List字面量的解决方案
问题原因
EF Core生成迁移时,需要将实体配置里的表达式转换成可序列化的C#字面量,但你用的WithProjection扩展中,List<ProjectionInfo>这个类型没有对应的CoreTypeMapping实现——运行时是内存直接执行表达式所以没问题,但设计时(迁移生成阶段)工具无法处理这个自定义类型,就抛出了错误。
解决办法
1. 让投影配置只在运行时生效
通过判断环境,在迁移生成的设计时环境下跳过这个配置,运行时再加载:
// 在DbContext的OnModelCreating方法中 bool isDesignTime = Environment.GetEnvironmentVariable("EF_DESIGN_TIME") == "true"; if (!isDesignTime) { builder.Entity<TopicModel>() .WithProjection( x => x.MenuIds, x => x.Menus.Select(y => y.Id).ToList() ); }
也可以通过IDesignTimeDbContextFactory创建设计时专用的DbContext实例,不在其中添加该投影配置。
2. 为自定义类型实现CoreTypeMapping
如果需要迁移工具识别这个类型,得自定义类型映射,实现GenerateCodeLiteral方法来生成对应的C#代码:
// 在DbContext中重写ConfigureConventions注册映射 protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.Properties<List<ProjectionInfo>>() .HaveTypeMapping(new ProjectionInfoListTypeMapping()); } // 自定义类型映射类 public class ProjectionInfoListTypeMapping : CoreTypeMapping { public ProjectionInfoListTypeMapping() : base(new TypeMappingInfo(typeof(List<ProjectionInfo>))) { } public override Expression GenerateCodeLiteral(object value) { var projectionList = (List<ProjectionInfo>)value; // 根据ProjectionInfo的实际构造逻辑生成表达式,示例如下 var elementExpressions = projectionList.Select(info => Expression.New( typeof(ProjectionInfo).GetConstructor(new[] { typeof(Expression), typeof(Expression) }), GenerateCodeLiteral(info.SourceExpression), GenerateCodeLiteral(info.TargetExpression) ) ); return Expression.NewArrayInit(typeof(ProjectionInfo), elementExpressions.ToArray()); } }
注意:要根据你ProjectionInfo类的实际属性和构造方法调整代码,确保能正确生成可编译的C#字面量。
3. 改用原生投影方式
放弃自定义扩展的配置,改用EF Core原生支持的方式实现投影:
比如给TopicModel添加只读计算属性:
public class TopicModel { // 其他属性... public ICollection<MenuModel> Menus { get; set; } public List<int> MenuIds => Menus?.Select(y => y.Id).ToList() ?? new List<int>(); }
然后在DbContext中标记该属性不映射到数据库:
builder.Entity<TopicModel>() .Property(x => x.MenuIds) .Metadata.SetIsTableColumn(false) .SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
内容的提问来源于stack exchange,提问作者Randy Hall
相关产品推荐
相关产品推荐

