EF Core技术问询:存储过程返回值绑定至模型或匿名类型
嘿,我来帮你搞定这两个EF Core里关于存储过程返回值绑定的问题,咱们一个一个说:
其实这个操作在EF Core里很直接,只要你的存储过程返回的列名和现有LocalModel的属性名完全匹配(注意数据库的大小写配置,比如SQL Server默认不区分大小写),直接用FromSqlRaw或者FromSqlInterpolated就能自动绑定,完全不需要额外的映射配置。
举个例子,假设你有一个叫GetLocalModels的存储过程,还有已经在DbContext里注册过的LocalModel:
// 调用存储过程并直接绑定到LocalModel var paramValue = 123; var results = context.Set<LocalModel>() .FromSqlRaw("EXEC GetLocalModels @Param = {0}", paramValue) .ToList();
这里的关键是context.Set<LocalModel>()会复用你已经为LocalModel配置的实体映射规则,只要存储过程返回的列和属性名对应上,EF Core就会自动把结果填充到LocalModel实例里,不用做任何额外的映射设置。
如果你的LocalModel不是映射到数据库表的DTO(比如只是一个用于接收返回值的类),那你可以把它配置为无键实体(Keyless Entity),这也不需要复杂的映射,只需要在DbContext的OnModelCreating里加一行配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<LocalModel>().HasNoKey(); }
之后同样用context.Set<LocalModel>().FromSqlRaw(...)来调用存储过程就行,效果是一样的。
EF Core本身不像旧版EF那样直接支持从存储过程返回匿名类型(因为它的查询API是强类型导向的),但我们可以通过两种方式实现类似的效果:
方法一:用现有实体/无键实体查询后投影到匿名类型
如果存储过程的返回列和你的LocalModel匹配,那最简单的方式就是先查询到LocalModel,再用Select投影成匿名类型:
var anonymousResults = context.Set<LocalModel>() .FromSqlRaw("EXEC GetLocalModels") .Select(model => new { ModelId = model.Id, ModelName = model.Name // 按需选择属性,重命名也可以 }) .ToList();
如果不想用现有LocalModel,也可以临时创建一个无键实体类(比如LocalProcResult),配置好无键规则后,查询它再投影到匿名类型,步骤和上面的无键实体配置一样。
方法二:直接用ADO.NET手动映射到匿名类型
如果连临时实体类都不想创建,那可以直接用EF Core底层的ADO.NET连接来执行存储过程,然后手动读取数据并创建匿名类型:
using (var command = context.Database.GetDbConnection().CreateCommand()) { command.CommandText = "EXEC GetLocalModels"; command.CommandType = System.Data.CommandType.StoredProcedure; // 打开连接(如果还没打开) context.Database.OpenConnection(); using (var reader = command.ExecuteReader()) { var anonymousList = new List<object>(); while (reader.Read()) { // 根据存储过程返回的列顺序或名称取值 anonymousList.Add(new { Id = reader.GetInt32(reader.GetOrdinal("Id")), Name = reader.GetString(reader.GetOrdinal("Name")) }); } return anonymousList; } }
这种方式更灵活,不需要任何实体类,但需要自己处理数据类型转换和列名匹配,适合临时的、简单的查询场景。
内容的提问来源于stack exchange,提问作者Pradeep H

