使用EF Power Tools序列化时遇InvalidOperationException的解决咨询
解决DbContext扩展方法执行时的InvalidOperationException异常
问题重现
使用以下DbContext扩展方法执行SQL操作时,抛出System.InvalidOperationException:
public static class DbContextExtensions { public static async Task<List<T>> SqlQueryAsync(this DbContext db, string sql, object[] parameters = null, CancellationToken cancellationToken = default) where T : class { if (parameters is null) { parameters = new object[] { }; } if (typeof(T).GetProperties().Any()) { return await db.Set<T>().FromSqlRaw(sql, parameters).ToListAsync(cancellationToken); } else { await db.Database.ExecuteSqlRawAsync(sql, parameters, cancellationToken); return default; } } }
错误信息:
System.InvalidOperationException: The type 'System.Threading.ExecutionContext&' of property 'Context' on type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1+AsyncStateMachineBox1[System.Collections.Generic.List`1[SpiritWMSApiCore2.Models.Unitech_ASNInfo_BOLResult],SpiritWMSApiCore2.Models.SIRISContextProcedures+<Unitech_ASNInfo_BOLAsync>d__56]' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types.
问题分析
错误核心原因:
- 扩展方法中通过
typeof(T).GetProperties().Any()判断是否执行查询的逻辑完全错误——EF Core的FromSqlRaw仅支持映射到数据库对象的合法实体类型,该判断无法区分实体类型和其他非法类型。 - 当调用逻辑出现上下文混乱(比如异步状态机类型被错误关联到泛型参数
T),EF Core会尝试序列化包含引用结构体(如ExecutionContext&)的类型,触发序列化校验失败。
解决方案
1. 拆分扩展方法,分离查询与非查询逻辑
将查询实体和执行非查询SQL的操作拆分为两个独立方法,避免逻辑混淆:
public static class DbContextExtensions { /// <summary> /// 执行SQL查询,返回实体列表(仅支持EF Core已配置的实体类型) /// </summary> public static async Task<List<T>> SqlQueryAsync<T>(this DbContext db, string sql, object[] parameters = null, CancellationToken cancellationToken = default) where T : class { parameters ??= Array.Empty<object>(); return await db.Set<T>().FromSqlRaw(sql, parameters).ToListAsync(cancellationToken); } /// <summary> /// 执行非查询SQL语句(如INSERT/UPDATE/DELETE),返回受影响行数 /// </summary> public static async Task<int> ExecuteSqlAsync(this DbContext db, string sql, object[] parameters = null, CancellationToken cancellationToken = default) { parameters ??= Array.Empty<object>(); return await db.Database.ExecuteSqlRawAsync(sql, parameters, cancellationToken); } }
2. 规范调用方式
- 查询实体时,明确指定合法的EF实体类型:
var result = await db.SqlQueryAsync<Unitech_ASNInfo_BOLResult>(yourSqlString, parametersArray); - 执行非查询操作时,调用专门的方法:
int affectedRows = await db.ExecuteSqlAsync(yourNonQuerySql, parametersArray);
3. 额外注意事项
- 确保泛型参数
T是EF Core中已配置的实体类型(存在对应的DbSet<T>或通过Fluent API完成映射),禁止传入匿名类型、包含引用结构体/指针类型的对象。 - 避免在异步方法中出现泛型参数上下文混乱的情况,确保调用时
T的类型明确指向目标实体。
内容的提问来源于stack exchange,提问作者sagesky36
相关产品推荐
相关产品推荐

