如何在 Entity Framework Core 中运行存储过程?
Posted
技术标签:
【中文标题】如何在 Entity Framework Core 中运行存储过程?【英文标题】:How to run stored procedures in Entity Framework Core? 【发布时间】:2015-02-19 05:45:52 【问题描述】:我在 ASP.NET Core 应用程序中使用 EF Core 1.0。您能否指出执行存储过程的正确方法? ObjectParameters
和 ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction
的旧方法不起作用。
【问题讨论】:
您需要运行 SP 并得到一些DbSet
的结果吗?还是直接运行?
我需要找回结果!
【参考方案1】:
现在解决了 EF Core 1.0 中对存储过程的支持,这也支持多个结果集的映射。
Check here for the fix details
你可以在c#中这样称呼它
var userType = dbContext.Set().FromSql("dbo.SomeSproc @Id = 0, @Name = 1", 45, "Ada");
【讨论】:
在这里找到另一个很好的例子 - dotnetjalps.com/2015/11/… 这是不言自明的。 尚不支持多个数据集。见github.com/aspnet/EntityFramework/issues/… 我的 2 美分:var UserId =1; _dbCtx.SetSet()
。只需获取The arguments for DbContext.Set<TEntity>() cannot be inferred from the usage
【参考方案2】:
EF7 中尚未实现存储过程支持(截至 7.0.0-beta3)。您可以使用 issue #245 跟踪此功能的进度。
现在,您可以使用 ADO.NET 以老式的方式进行操作。
var connection = (SqlConnection)context.Database.AsSqlServer().Connection.DbConnection;
var command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "MySproc";
command.Parameters.AddWithValue("@MyParameter", 42);
command.ExecuteNonQuery();
【讨论】:
那是#624。 ;) 您始终可以在 ADO.NET 连接上执行此操作:context.Database.AsRelational().Connection.DbConnection
。
@JimWooley 这似乎有点不道德......但是是的,现在使用FromSql
。
@JimWooley LOL,不确定您是否意识到这一点,但您否决了 EF 团队中一位主要开发人员的回答... :)
@RichardMarskell-Drackir *** 的答案在很大程度上是一个时间点的事情。您真的希望每个人在剩下的时间里保持所有答案都是最新的吗?提问者应该选择不同的答案,或者社区应该支持出现的更好的答案。否决票的错误形式。
@bricelam - 我不同意答案应该被视为时间点。我偶尔会回到旧的高投票答案,看看是否有任何变化,所以新的搜索仍然相关,但我意识到并不是每个人都这样做。很多时候,我从搜索中来到 SO 并开始使用接受的答案,只是后来才发现有一个更好的答案。我同意如果提问者更新答案会很好,但他们很可能会得到他们想要的并继续前进。无论如何,我认为来自谷歌的人知道有更好的方法来做到这一点会很有帮助。 :)【参考方案3】:
要执行存储过程,请使用执行 RAW SQL 查询的FromSql 方法
例如
var products= context.Products
.FromSql("EXECUTE dbo.GetProducts")
.ToList();
与参数一起使用
var productCategory= "Electronics";
var product = context.Products
.FromSql("EXECUTE dbo.GetProductByCategory 0", productCategory)
.ToList();
或
var productCategory= new SqlParameter("productCategory", "Electronics");
var product = context.Product
.FromSql("EXECUTE dbo.GetProductByName @productCategory", productCategory)
.ToList();
执行 RAW SQL 查询或存储过程存在一定的限制。您不能将其用于 INSERT/UPDATE/DELETE。如果要执行 INSERT、UPDATE、DELETE 查询,请使用 ExecuteSqlCommand
var categoryName = "Electronics";
dataContext.Database
.ExecuteSqlCommand("dbo.InsertCategory @p0", categoryName);
【讨论】:
方法ExecuteSqlCommand
现已过时。请参阅ExecuteSqlCommand Method 可能的替代方案是ExecuteSqlRaw
和ExecuteSqlInterpolated
。【参考方案4】:
EF Core 对存储过程的支持与早期版本的 EF Code 类似。
您需要通过从 EF 继承 DbContext 类来创建您的 DbContext 类。存储过程使用 DbContext 执行。
第一步是编写一个从 DbContext 创建 DbCommand 的方法。
public static DbCommand LoadStoredProc(
this DbContext context, string storedProcName)
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = storedProcName;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
return cmd;
要将参数传递给存储过程,请使用以下方法。
public static DbCommand WithSqlParam(
this DbCommand cmd, string paramName, object paramValue)
if (string.IsNullOrEmpty(cmd.CommandText))
throw new InvalidOperationException(
"Call LoadStoredProc before using this method");
var param = cmd.CreateParameter();
param.ParameterName = paramName;
param.Value = paramValue;
cmd.Parameters.Add(param);
return cmd;
最后,使用 MapToList 方法将结果映射到自定义对象列表中。
private static List<T> MapToList<T>(this DbDataReader dr)
var objList = new List<T>();
var props = typeof(T).GetRuntimeProperties();
var colMapping = dr.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
if (dr.HasRows)
while (dr.Read())
T obj = Activator.CreateInstance<T>();
foreach (var prop in props)
var val =
dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
objList.Add(obj);
return objList;
现在我们准备好使用 ExecuteStoredProc 方法执行存储过程,并将其映射到类型为 T 传入的 List。
public static async Task<List<T>> ExecuteStoredProc<T>(this DbCommand command)
using (command)
if (command.Connection.State == System.Data.ConnectionState.Closed)
command.Connection.Open();
try
using (var reader = await command.ExecuteReaderAsync())
return reader.MapToList<T>();
catch(Exception e)
throw (e);
finally
command.Connection.Close();
例如,要使用两个参数“firstparamname”和“secondparamname”执行一个名为“StoredProcedureName”的存储过程,这就是实现。
List<MyType> myTypeList = new List<MyType>();
using(var context = new MyDbContext())
myTypeList = context.LoadStoredProc("StoredProcedureName")
.WithSqlParam("firstparamname", firstParamValue)
.WithSqlParam("secondparamname", secondParamValue).
.ExecureStoredProc<MyType>();
【讨论】:
【参考方案5】:我尝试了所有其他解决方案,但都没有为我工作。但我找到了一个合适的解决方案,它可能对这里的人有所帮助。
要调用存储过程并将结果放入 EF Core 中的模型列表中,我们必须遵循 3 个步骤。
第 1 步。
您需要添加一个新类,就像您的实体类一样。哪个应该具有您的 SP 中所有列的属性。例如,如果您的 SP 返回两个名为 Id
和 Name
的列,那么您的新类应该类似于
public class MySPModel
public int Id get; set;
public string Name get; set;
第 2 步。
然后您必须为您的 SP 将一个 DbQuery
属性添加到您的 DBContext 类中。
public partial class Sonar_Health_AppointmentsContext : DbContext
public virtual DbSet<Booking> Booking get; set; // your existing DbSets
...
public virtual DbQuery<MySPModel> MySP get; set; // your new DbQuery
...
第 3 步。
现在您将能够从您的 DBContext 调用您的 SP 并获取结果。
var result = await _context.Query<MySPModel>().AsNoTracking().FromSql(string.Format("EXEC 0 1", functionName, parameter)).ToListAsync();
我使用的是通用 UnitOfWork & Repository。所以我执行 SP 的功能是
/// <summary>
/// Execute function. Be extra care when using this function as there is a risk for SQL injection
/// </summary>
public async Task<IEnumerable<T>> ExecuteFuntion<T>(string functionName, string parameter) where T : class
return await _context.Query<T>().AsNoTracking().FromSql(string.Format("EXEC 0 1", functionName, parameter)).ToListAsync();
希望对某人有所帮助!!!
【讨论】:
我希望避免这样做。我编写了自己的库(前 EF)来处理动态数据集(例如连接等),然后完美地工作。每个人都在抱怨,所以我搬到了 EF,你现在不能这样做。你猜怎么着,他们让我重写我的库。我的反应并不愉快。【参考方案6】:"(SqlConnection)context"
-- 这种类型转换不再有效。你可以这样做:"SqlConnection context;
".AsSqlServer()"
-- 不存在。
"command.ExecuteNonQuery();"
-- 不返回结果。 reader=command.ExecuteReader()
确实有效。
使用 dt.load(reader)... 那么您必须将框架从 5.0 切换回 4.51,因为 5.0 尚不支持数据表/数据集。注意:这是 VS2015 RC。
【讨论】:
【参考方案7】:ExecuteSqlCommand
和ExecuteSqlCommandAsync
遇到了很多麻烦,IN 参数很容易,但 OUT 参数很难。
我不得不像这样恢复使用DbCommand
-
DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "dbo.sp_DoSomething";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar) Value = "Steve" );
cmd.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar) Value = "Smith" );
cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.BigInt) Direction = ParameterDirection.Output );
我在this post 中写了更多关于它的内容。
【讨论】:
【参考方案8】:目前 EF 7 或 EF Core 不支持在设计器中导入存储过程并直接调用它们的旧方法。您可以查看路线图以了解未来将支持的内容: EF core roadmap.
所以现在最好使用 SqlConnection 来调用存储过程或任何原始查询,因为您不需要整个 EF 来完成这项工作。这里有两个例子:
调用返回单个值的存储过程。在这种情况下为字符串。
CREATE PROCEDURE [dbo].[Test]
@UserName nvarchar(50)
AS
BEGIN
SELECT 'Name is: '+@UserName;
END
调用返回列表的存储过程。
CREATE PROCEDURE [dbo].[TestList]
AS
BEGIN
SELECT [UserName], [Id] FROM [dbo].[AspNetUsers]
END
要调用这些存储过程,最好创建一个包含所有这些函数的静态类,例如,我称之为DataAccess类,如下:
public static class DataAccess
private static string connectionString = ""; //Your connection string
public static string Test(String userName)
using (SqlConnection conn = new SqlConnection(connectionString))
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("dbo.Test", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
// execute the command
using (var rdr = cmd.ExecuteReader())
if (rdr.Read())
return rdr[0].ToString();
else
return null;
public static IList<Users> TestList()
using (SqlConnection conn = new SqlConnection(connectionString))
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("dbo.TestList", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// execute the command
using (var rdr = cmd.ExecuteReader())
IList<Users> result = new List<Users>();
//3. Loop through rows
while (rdr.Read())
//Get each column
result.Add(new Users() UserName = (string)rdr.GetString(0), Id = rdr.GetString(1) );
return result;
而用户类是这样的:
public class Users
public string UserName set; get;
public string Id set; get;
顺便说一句,您无需担心为每个对 sql 的请求打开和关闭连接的性能,因为 asp.net 正在为您管理这些。 我希望这会有所帮助。
【讨论】:
【参考方案9】:我发现这个扩展非常有用:StoredProcedureEFCore
那么用法是这样的
List<Model> rows = null;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 300L)
.AddParam("limitOut", out IOutParam<long> limitOut)
.Exec(r => rows = r.ToList<Model>());
long limitOutValue = limitOut.Value;
ctx.LoadStoredProc("dbo.ReturnBoolean")
.AddParam("boolean_to_return", true)
.ReturnValue(out IOutParam<bool> retParam)
.ExecNonQuery();
bool b = retParam.Value;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 1L)
.ExecScalar(out long l);
【讨论】:
【参考方案10】:由于我的团队已经同意我们将使用通用 UnitOfWork 模式,所以我在创建自己的解决方案时采取了一些大家的解决方案。
我还发布了一些 UnitOfWork 代码,以便您了解我为什么需要这样实现它。
public interface IUnitOfWork : IDisposable
DbContext Context get;
Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class;
接口实现:
public class UnitOfWork : IUnitOfWork
public DbContext Context get; private set;
/// <summary>
/// Execute procedure from database using it's name and params that is protected from the SQL injection attacks.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="storedProcName">Name of the procedure that should be executed.</param>
/// <param name="procParams">Dictionary of params that procedure takes. </param>
/// <returns>List of objects that are mapped in T type, returned by procedure.</returns>
public async Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class
DbConnection conn = Context.Database.GetDbConnection();
try
if(conn.State != ConnectionState.Open)
await conn.OpenAsync();
await using (DbCommand command = conn.CreateCommand())
command.CommandText = storedProcName;
command.CommandType = CommandType.StoredProcedure;
foreach (KeyValuePair<string, object> procParam in procParams)
DbParameter param = command.CreateParameter();
param.ParameterName = procParam.Key;
param.Value = procParam.Value;
command.Parameters.Add(param);
DbDataReader reader = await command.ExecuteReaderAsync();
List<T> objList = new List<T>();
IEnumerable<PropertyInfo> props = typeof(T).GetRuntimeProperties();
Dictionary<string, DbColumn> colMapping = reader.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
if (reader.HasRows)
while (await reader.ReadAsync())
T obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in props)
object val =
reader.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
objList.Add(obj);
reader.Dispose();
return objList;
catch (Exception e)
System.Diagnostics.Debug.WriteLine(e.Message, e.InnerException);
finally
conn.Close();
return null; // default state
示例用法如下:
public class MyService : IMyService
private readonly IUnitOfWork _uow;
public MyService(IUnitOfWork uow)
_uow = uow;
public async Task<List<TreeViewModel>> GetTreeOptions()
var procParams = new Dictionary<string, object>()
"@Id", 2
;
var result = await _uow.ExecuteStoredProc<TreeViewModel>("FetchTreeProcedure", procParams);
return result;
【讨论】:
【参考方案11】:使用 mysql 连接器和 Entity Framework Core 2.0
我的问题是我遇到了像 fx. Ex.Message = "'FromSql' 操作的结果中不存在所需的列 'body'。"。因此,为了以这种方式通过存储过程获取行,您必须返回与 DBSet 关联的实体类型的所有列,即使您不需要为当前请求访问所有列。
var result = _context.DBSetName.FromSql($"call storedProcedureName()").ToList();
或带参数
var result = _context.DBSetName.FromSql($"call storedProcedureName(optionalParam1)").ToList();
【讨论】:
【参考方案12】:我将 Entity Framework Core 与我的 ASP.Net Core 3.x WebAPI 一起使用。我希望我的终点之一只是执行一个特定的存储过程,这就是我需要的代码:
namespace MikesBank.Controllers
[Route("api/[controller]")]
[ApiController]
public class ResetController : ControllerBase
private readonly MikesBankContext _context;
public ResetController(MikesBankContext context)
_context = context;
[HttpGet]
public async Task<ActionResult> Get()
try
using (DbConnection conn = _context.Database.GetDbConnection())
if (conn.State != System.Data.ConnectionState.Open)
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "Reset_Data";
await cmd.ExecuteNonQueryAsync();
return new OkObjectResult(1);
catch (Exception ex)
return new BadRequestObjectResult(ex.Message);
注意我需要如何获取已注入的DbContext
,但我还需要Open()
这个连接。
【讨论】:
【参考方案13】:我使用了 https://github.com/verdie-g/StoredProcedureEFCore,EnterpriseLibrary.Data.NetCore,EFCor.SqlServer,EFCore.Tools 的 StoredProcedureEFCore nuget 包
我尝试使用 Repository pattern 的 DbFirst 方法.. 我想是的
startup.cs
ConfigureServices(IServiceCollection services)
services.AddDbContext<AppDbContext>(opt => opt
.UseSqlServer(Configuration.GetConnectionString("SampleConnectionString")));
services.AddScoped<ISomeDAL, SomeDAL>();
public class AppDbContext : DbContext
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
ISomeDAl 接口有GetPropertiesResponse GetAllPropertiesByCity(int CityId);
public class SomeDAL : ISomeDAL
private readonly AppDbContext context;
public SomeDAL(AppDbContext context)
this.context = context;
public GetPropertiesResponse GetAllPropertiesByCity(int CityId)
//Create Required Objects for response
//wont support ref Objects through params
context.LoadStoredProc(SQL_STATEMENT)
.AddParam("CityID", CityId).Exec( r =>
while (r.Read())
ORMapping<GenericRespStatus> orm = new ORMapping<GenericRespStatus>();
orm.AssignObject(r, _Status);
if (r.NextResult())
while (r.Read())
Property = new Property();
ORMapping<Property> orm = new ORMapping<Property>();
orm.AssignObject(r, Property);
_propertyDetailsResult.Add(Property);
);
return new GetPropertiesResponseStatus=_Status,PropertyDetails=_propertyDetailsResult;
public class GetPropertiesResponse
public GenericRespStatus Status;
public List<Property> PropertyDetails;
public GetPropertiesResponse()
PropertyDetails = new List<Property>();
public class GenericRespStatus
public int ResCode get; set;
public string ResMsg get; set;
internal class ORMapping<T>
public void AssignObject(IDataReader record, T myClass)
PropertyInfo[] propertyInfos = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
if (propertyInfos.Any(obj => obj.Name == record.GetName(i))) //&& record.GetValue(i) != DBNull.Value
propertyInfos.Single(obj => obj.Name == record.GetName(i)).SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)));
【讨论】:
【参考方案14】:如果您使用 EntityFrameworkCore 从 Informix 执行存储过程,则需要包含命令 EXECUTE PROCEDURE
var spresult = _informixContext.procdata.FromSql("EXECUTE PROCEDURE dummyproc (0,1,2)", parameters: new[] p0, p1,p2 ).ToList();
【讨论】:
【参考方案15】:无需执行任何操作...当您为代码优先方法初始化创建 dbcontext 时 fluent API 区域下方的命名空间列出 sp 并在您想要的另一个地方使用它。
public partial class JobScheduleSmsEntities : DbContext
public JobScheduleSmsEntities()
: base("name=JobScheduleSmsEntities")
Database.SetInitializer<JobScheduleSmsEntities>(new CreateDatabaseIfNotExists<JobScheduleSmsEntities>());
public virtual DbSet<Customer> Customers get; set;
public virtual DbSet<ReachargeDetail> ReachargeDetails get; set;
public virtual DbSet<RoleMaster> RoleMasters get; set;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
//modelBuilder.Types().Configure(t => t.MapToStoredProcedures());
//modelBuilder.Entity<RoleMaster>()
// .HasMany(e => e.Customers)
// .WithRequired(e => e.RoleMaster)
// .HasForeignKey(e => e.RoleID)
// .WillCascadeOnDelete(false);
public virtual List<Sp_CustomerDetails02> Sp_CustomerDetails()
//return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Sp_CustomerDetails02>("Sp_CustomerDetails");
// this.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails");
using (JobScheduleSmsEntities db = new JobScheduleSmsEntities())
return db.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails").ToList();
public partial class Sp_CustomerDetails02
public long? ID get; set;
public string Name get; set;
public string CustomerID get; set;
public long? CustID get; set;
public long? Customer_ID get; set;
public decimal? Amount get; set;
public DateTime? StartDate get; set;
public DateTime? EndDate get; set;
public int? CountDay get; set;
public int? EndDateCountDay get; set;
public DateTime? RenewDate get; set;
public bool? IsSMS get; set;
public bool? IsActive get; set;
public string Contact get; set;
【讨论】:
【参考方案16】:根据存储过程的 Select 查询中的字段创建特殊类。 例如我将这个类称为 ResulData
添加到你 EF 的上下文中
modelBuilder.Entity<ResultData>(e =>
e.HasNoKey();
);
这是一个使用存储过程获取数据的示例函数
public async Task<IEnumerable<ResultData>> GetDetailsData(int id, string name)
var pId = new SqlParameter("@Id", id);
var pName = new SqlParameter("@Name", name);
return await _context.Set<ResultData>()
.FromSqlRaw("Execute sp_GetDeailsData @Id @Name", parameters: new[] pId, pName )
.ToArrayAsync();
【讨论】:
【参考方案17】:我正在使用 Entity Framework Core。对存储过程和即席查询的支持不像在 Framework 中那样流畅。
以下是一些示例供将来参考:
根据存储过程的结果填充实体列表:
[dbo].[GetUnarchivedJobs]
存储过程返回与Job
实体匹配的记录列表。
我们可以使用Jobs
属性上的FromSqlInterpolated()
方法来调用存储过程并返回Job
的列表。
NoTracking()
用于加速性能,在这种情况下我们不会更新实体。
using Microsoft.EntityFrameworkCore;
public class DbContext : Microsoft.EntityFrameworkCore.DbContext
protected DbSet<Job> Jobs get; set;
// Populate a list of entities from the results of a stored procedure
public Task<List<Job>> GetUnarchivedJobs(int maxQty, CancellationToken cancellationToken) =>
Jobs.FromSqlInterpolated($"EXEC [dbo].[GetUnarchivedJobs] @MaxQty = maxQty")
.AsNoTracking()
.ToListAsync(cancellationToken)
;
public DbContext(DbContextOptions<DbContext> options) : base(options)
将整数数组发送到存储过程:
[dbo].[SetJobListArchiveFlags]
存储过程有一个 integer_list_tbltype
类型的参数。
我们需要创建一个DataTable
来匹配integer_list_tbltype
类型,它有一个名为n
的列。
int
值需要添加到DataTable
。
SqlParameter
用于将填充的DataTable
传递给存储过程。
因为我们没有填充任何实体,所以我们需要使用 Database
属性上的方法来调用存储过程。
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Data;
public class DbContext : Microsoft.EntityFrameworkCore.DbContext
// Send an array of integers to a stored procedure
public async Task<int> MarkJobsAsArchived(IEnumerable<int> jobIds, CancellationToken cancellationToken)
// This DataTable matches the `integer_list_tbltype` db type
var table = new DataTable();
table.Columns.Add("n", typeof(int));
foreach (var id in jobIds) table.Rows.Add(id);
var parameter = new SqlParameter("@jobIds", SqlDbType.Structured);
parameter.Value = table;
parameter.TypeName = "integer_list_tbltype";
var rowsUpdatedCount = await Database.ExecuteSqlRawAsync("EXEC [dbo].[SetJobListArchiveFlags] @jobIds", new[] parameter , cancellationToken);
return rowsUpdatedCount;
【讨论】:
【参考方案18】:我们应该在模型中为 db 上下文创建一个带有 DbQuery 而不是 DbSet 的属性,如下所示...
public class MyContextContext : DbContext
public virtual DbQuery<CheckoutInvoiceModel> CheckoutInvoice get; set;
比一个可以用来返回结果的方法
public async Task<IEnumerable<CheckoutInvoiceModel>> GetLabReceiptByReceiptNo(string labReceiptNo)
var listing = new List<CheckoutInvoiceModel>();
try
var sqlCommand = $@"[dbo].[Checkout_GetLabReceiptByReceiptNo] labReceiptNo";
listing = await db.Set<CheckoutInvoiceModel>().FromSqlRaw(sqlCommand).ToListAsync();
catch (Exception ex)
return null;
return listing;
从上面的例子中,我们可以使用任何你喜欢的选项。
希望对您有所帮助!
【讨论】:
您从不使用此属性CheckoutInvoice
。而且还不清楚LoadStoredProc
来自哪里。
是的,这可以在 DbContext 中添加 CheckoutInvoice,但应该是 DbQuery,而不是 DbSet。好吧,LoadStoredProc 来自 以上是关于如何在 Entity Framework Core 中运行存储过程?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Entity Framework Core 2 中播种?
如何处置 Entity Framework Core 内存数据库
如何在 Entity Framework Core 中将连接字符串传递给 DBContext?
如何使用 Entity Framework Core 正确保存 DateTime?
如何在 .NET Core 3.0 Entity Framework 中执行组加入?
请问在 .NET Core 中如何让 Entity Framework Core 在日志中记录由 LINQ 生成的SQL语句?