如何使用Entity Framework Core消费返回JSON的存储过程?
解决EF Core消费返回JSON的存储过程问题
这个问题我之前也踩过坑!EF Core确实没法直接把JObject当成实体来用,因为它根本不在你的DbContext模型注册列表里,所以才会抛出那个错误。下面给你几个实用的解决方案,按需选择:
方案一:通过临时实体类读取JSON字符串再反序列化
这是最常用的方法,核心思路是先把存储过程返回的JSON字符串读出来,再转成JObject或者你需要的强类型:
- 创建临时实体类:用来接收存储过程返回的单列JSON结果
public class JsonResultContainer { // 注意属性名要和存储过程返回的列名一致,或者在SQL里指定别名 public string JsonData { get; set; } }
- 在DbContext中注册无键实体:因为这个类不需要对应数据库表,所以配置成无键实体即可
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<JsonResultContainer>().HasNoKey(); }
- 调用存储过程并反序列化:
// 读取JSON字符串 var jsonString = _db.Set<JsonResultContainer>() .FromSqlRaw("EXEC dbo.Mine @customerid = {0}", _user.guid) .Select(result => result.JsonData) .FirstOrDefault(); // 转成JObject var foo = JsonConvert.DeserializeObject<JObject>(jsonString);
小贴士:如果存储过程返回的列名不是
JsonData,记得在存储过程的SELECT语句里加别名,比如SELECT ... FOR JSON PATH AS JsonData。
方案二:直接用强类型实体(推荐如果JSON结构固定)
如果你的存储过程返回的JSON结构是固定的,直接创建对应的实体类会更优雅,避免用JObject的动态操作:
- 创建对应JSON结构的实体类:
public class CustomerProfile { public Guid CustomerId { get; set; } public string FullName { get; set; } public List<OrderItem> RecentOrders { get; set; } } public class OrderItem { public int OrderId { get; set; } public DateTime OrderDate { get; set; } public decimal TotalAmount { get; set; } }
- 读取并反序列化为强类型:
var jsonString = _db.Set<JsonResultContainer>() .FromSqlRaw("EXEC dbo.Mine @customerid = {0}", _user.guid) .Select(result => result.JsonData) .FirstOrDefault(); var customerProfile = JsonConvert.DeserializeObject<CustomerProfile>(jsonString);
方案三:绕过EF Core,直接用ADO.NET方式
如果不想创建任何临时类,也可以直接用DbContext底层的数据库连接来执行存储过程:
using (var connection = _db.Database.GetDbConnection()) { await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = "dbo.Mine"; command.CommandType = CommandType.StoredProcedure; // 添加参数 var customerIdParam = command.CreateParameter(); customerIdParam.ParameterName = "@customerid"; customerIdParam.Value = _user.guid; command.Parameters.Add(customerIdParam); using (var reader = await command.ExecuteReaderAsync()) { if (reader.Read()) { var jsonString = reader.GetString(0); var foo = JsonConvert.DeserializeObject<JObject>(jsonString); // 这里处理你的JObject } } } }
为什么你的原代码会报错?
你之前用_db.Set<JObject>()的问题在于:EF Core的Set<T>()要求T是一个在DbContext模型中注册的实体类(要么是对应数据库表的实体,要么是像方案一中的无键实体),而JObject是Newtonsoft.Json里的动态类型,根本没有被注册到你的DbContext模型里,所以EF Core不知道怎么处理它,就抛出了那个错误。
内容的提问来源于stack exchange,提问作者Max Favilli
相关产品推荐
相关产品推荐

