如何使用EntityFramework 7和Asp.Net 5调用SQL存储过程

Sub*_*kar 5 c# sql-server ef-database-first entity-framework-core asp.net-core-mvc

在过去的几天里,我正在寻找一些关于如何使用控制器方法调用Stored Procedure内部的教程.Web APIEntityFramework 7

我通过的所有教程都反过来展示它,即Code First接近.但我已经有了一个数据库,我需要用它来构建一个Web API.各种业务逻辑已经编写为存储过程和视图,我必须使用来自Web API的那些逻辑.

问题1:这是否可以继续使用上述Database First方法EF7并使用数据库对象?

EntityFramework 6.1.3通过以下NuGet命令安装到我的包中:

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,而是我想ORM使用EntityFramework

2)如果EntityFramework 6.1.3有来电的能力Stored Procs,并Views从已经存在的数据库,我怎么能解决错误(截图)?

实现这一目标的最佳做法是什么?

Ole*_*leg 11

我希望我正确理解你的问题.例如dbo.spGetSomeData,您在数据库中存在STORED PROCEDURE,它返回包含某些字段的某些项的列表,您需要从Web API方法提供数据.

实施可以是以下几点.您可以定义一个空的 DbContext:

public class MyDbContext : DbContext
{
}
Run Code Online (Sandbox Code Playgroud)

appsettings.json使用连接字符串定义数据库

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=MyDb;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您应该使用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<MyDbContext>(options => {
                options.UseSqlServer(Configuration["ConnectionString"]);
            });
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以按以下方式实施WebApi操作:

[Route("api/[controller]")]
public class MyController : Controller
{
    public MyDbContext _context { get; set; }

    public MyController([FromServices] MyDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async IEnumerable<object> Get()
    {
        var returnObject = new List<dynamic>();

        using (var cmd = _context.Database.GetDbConnection().CreateCommand()) {
            cmd.CommandText = "exec dbo.spGetSomeData";
            cmd.CommandType = CommandType.StoredProcedure;
            // set some parameters of the stored procedure
            cmd.Parameters.Add(new SqlParameter("@someParam",
                SqlDbType.TinyInt) { Value = 1 });

            if (cmd.Connection.State != ConnectionState.Open)
                cmd.Connection.Open();

            var retObject = new List<dynamic>();
            using (var dataReader = await cmd.ExecuteReaderAsync())
            {
                while (await dataReader.ReadAsync())
                {
                    var dataRow = new ExpandoObject() as IDictionary<string, object>;
                    for (var iFiled = 0; iFiled < dataReader.FieldCount; iFiled++) {
                        // one can modify the next line to
                        //   if (dataReader.IsDBNull(iFiled))
                        //       dataRow.Add(dataReader.GetName(iFiled), dataReader[iFiled]);
                        // if one want don't fill the property for NULL
                        // returned from the database
                        dataRow.Add(
                            dataReader.GetName(iFiled),
                            dataReader.IsDBNull(iFiled) ? null : dataReader[iFiled] // use null instead of {}
                        );
                    }

                    retObject.Add((ExpandoObject)dataRow);
                }
            }
            return retObject;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码只是执行使用exec dbo.spGetSomeData并使用dataRader读取所有结果并保存在dynamic对象中.如果您$.ajax打电话,api/My您将获得从中返回的数据dbo.spGetSomeData,您可以直接在JavaScript代码中使用.上面的代码非常透明.返回的数据集中的字段名称dbo.spGetSomeData将是JavaScript代码中属性的名称.您无需以任何方式管理C#代码中的任何实体类.您的C#代码没有从存储过程返回的字段名称.因此,如果您要扩展/更改dbo.spGetSomeData(重命名某些字段,添加新字段)的代码,则只需调整JavaScript代码,但不需要调整C#代码.


Chr*_*att 5

DbContext有一个Database属性,它保存与数据库的连接,您可以随意执行以下操作:

context.Database.SqlQuery<Foo>("exec [dbo].[GetFoo] @Bar = {0}", bar);
Run Code Online (Sandbox Code Playgroud)

但是,我建议您不要在Web Api操作中执行此操作,而是向您的上下文或与您的上下文交互的任何服务/存储库添加方法.然后在您的操作中调用此方法.理想情况下,您希望将所有SQL内容保存在一个位置.

  • 这*不是*“EF-ish”方式。EF 在 EF7 中放弃了对 EDMX 的支持。EDM 设计器已被弃用,最好摆脱它。 (2认同)