如何使用EntityFramework 7和Asp.Net 5调用SQL存储过程
在过去的几天里,我正在寻找一些关于如何使用EntityFramework 7
从Web API
控制器方法中调用Stored Procedure
教程。
我通过的所有教程都反过来展示了它,即Code First
方法。 但我已经有了一个数据库,我需要用它来构建一个Web API
。 各种业务逻辑已经编写为存储过程和视图,我必须使用来自Web API的那些逻辑。
问题1:这是否可以继续使用EF7
Database First
方法并使用上面的数据库对象?
我通过以下NuGet
命令将EntityFramework 6.1.3
安装到我的包中:
install-package EntityFramework
,它将版本6.1.3添加到我的项目中,但立即开始显示错误消息(请参阅下面的屏幕截图)。 我不清楚如何解决这个问题。
我有另一个测试项目,在project.json
我可以看到两个如下的条目:
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final", "EntityFramework.MicrosoftSqlServer.Design": "7.0.0-rc1-final",
但是,当我在Nu-Get
包管理器中搜索时,我看不到这个版本! 只有6.1.3即将到来。
我的主要目标是从现有数据库中使用已编写的存储过程和视图。
1)我不想使用ADO.Net
,而是想使用EntityFramework
来使用ORM
2)如果EntityFramework 6.1.3
能够从现有数据库调用Stored Procs
和Views
,我如何解决错误(截图)?
实现这一目标的最佳做法是什么?
我希望我正确理解你的问题。 您在数据库中有现有的STORED PROCEDURE,例如dbo.spGetSomeData
,它返回包含某些字段的某些项的列表,您需要从Web API方法提供数据。
实施可以是以下几点。 您可以定义一个空的 DbContext
如:
public class MyDbContext : DbContext { }
并使用数据库的连接字符串定义appsettings.json
{ "Data": { "DefaultConnection": { "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=MyDb;Trusted_Connection=True;MultipleActiveResultSets=true" } } }
您应该使用Microsoft.Extensions.DependencyInjection
将MyDbContext
添加到
public class Startup { // property for holding configuration public IConfigurationRoot Configuration { get; set; } public Startup(IHostingEnvironment env) { // Set up configuration sources. var builder = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); .AddEnvironmentVariables(); // save the configuration in Configuration property Configuration = builder.Build(); } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc() .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); services.AddEntityFramework() .AddSqlServer() .AddDbContext(options => { options.UseSqlServer(Configuration["ConnectionString"]); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... } }
现在,您可以按以下方式实施WebApi操作:
[Route("api/[controller]")] public class MyController : Controller { public MyDbContext _context { get; set; } public MyController([FromServices] MyDbContext context) { _context = context; } [HttpGet] public async IEnumerable
上面的代码只使用exec dbo.spGetSomeData
执行,并使用dataRader读取所有结果并保存在dynamic
对象中。 如果您要从api/My
进行$.ajax
调用,您将获得从dbo.spGetSomeData
返回的数据,您可以直接在JavaScript代码中使用它。 上面的代码非常透明。 dbo.spGetSomeData
返回的数据集中的字段名称将是JavaScript代码中属性的名称。 您无需以任何方式管理C#代码中的任何实体类。 您的C#代码没有从存储过程返回的字段名称。 因此,如果您要扩展/更改dbo.spGetSomeData
的代码(重命名某些字段,添加新字段),则只需调整JavaScript代码,但不需要调整C#代码。
DbContext
有一个Database
属性,它保存与数据库的连接,您可以随意执行以下操作:
context.Database.SqlQuery("exec [dbo].[GetFoo] @Bar = {0}", bar);
但是,我建议您不要在Web Api操作中执行此操作,而是向上下文或与上下文交互的任何服务/存储库添加方法。 然后在您的操作中调用此方法。 理想情况下,您希望将所有SQL内容保存在一个位置。
正如上面的答案,你可以简单地使用FromSQL()而不是SqlQuery <>()。
context.Set().FromSql("[dbo].[GetFoo] @Bar = {0}", 45);
对于Database first方法,您必须使用Scaffold-DbContext命令
安装Nuget包Microsoft.EntityFrameworkCore.Tools和Microsoft.EntityFrameworkCore.SqlServer.Design
Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
但这不会得到你的存储过程。 它仍处于工作中,跟踪问题#245
但是,要执行存储过程,请使用执行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);
使用MySQL连接器和Entity Framework核心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();