EF Core 7执行SqlQuery查询自定义类型报错,EF 6可正常运行求助
在EF Core 7中解决自定义类型SqlQuery报错的方案
问题场景
执行以下SQL查询时触发错误:
SELECT * FROM TABLE(MY_CUSTOM_FU(:my_param))
报错信息:
System.InvalidOperationException: 'The element type 'MyCustomRow' used in 'SqlQuery' method is not natively supported by your database provider. Either use a supported element type, or use ModelConfigurationBuilder.DefaultTypeMapping to define a mapping for your type.'
该查询在EF 6中通过SqlQueryRaw可以正常执行:
rows = Database.SqlQueryRaw<MyCustomRow>("SELECT * FROM TABLE(MY_CUSTOM_FU(:my_param))", myParam);
解决方法
1. 配置自定义类型的默认映射
在你的DbContext的OnModelCreating方法中,使用ModelConfigurationBuilder为MyCustomRow定义类型转换逻辑,适配数据库提供商的要求:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.DefaultTypeMapping<MyCustomRow>() .HasConversion( // 将MyCustomRow转换为数据库支持的类型(示例逻辑,需根据实际数据库调整) row => { // 比如Oracle环境下构建OracleDataRecord,SqlServer下可对应SqlDataRecord // 需匹配存储过程返回的列结构 }, // 从数据库返回值转换回MyCustomRow dbValue => { var customRow = new MyCustomRow(); // 根据数据库返回的字段赋值给customRow的属性 customRow.Id = dbValue.GetInt32(0); customRow.Name = dbValue.GetString(1); return customRow; }); }
2. 手动读取DataReader并转换
绕过EF Core的类型映射,直接使用DataReader读取结果后手动映射到MyCustomRow:
using var reader = await Database.ExecuteSqlRawAsync("SELECT * FROM TABLE(MY_CUSTOM_FU(:my_param))", myParam); var rows = new List<MyCustomRow>(); while (reader.Read()) { var row = new MyCustomRow { // 根据查询结果的列顺序或名称赋值 PropertyA = reader.GetInt32(reader.GetOrdinal("PropertyA")), PropertyB = reader.GetString(reader.GetOrdinal("PropertyB")) // 其他属性依次配置 }; rows.Add(row); } await reader.CloseAsync();
3. 将MyCustomRow注册为无键实体
如果MyCustomRow的结构适合作为EF Core实体(无需对应物理表),可以将其注册为无键实体,让EF Core识别该类型:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 注册为无键实体,因为自定义返回类型通常没有主键 modelBuilder.Entity<MyCustomRow>().HasNoKey(); }
之后即可正常使用SqlQuery:
rows = await Database.SqlQuery<MyCustomRow>("SELECT * FROM TABLE(MY_CUSTOM_FU(:my_param))", myParam).ToListAsync();
内容的提问来源于stack exchange,提问作者Djamel Besseghir
相关产品推荐
相关产品推荐

