Entity framework 使用实体框架核心生成和访问存储过程

Entity framework 使用实体框架核心生成和访问存储过程,entity-framework,asp.net-core,entity-framework-core,Entity Framework,Asp.net Core,Entity Framework Core,我正在使用Visual Studio 2017实现Asp.Net核心Web API、实体框架核心、数据库优先方法。我已经成功地基于现有数据库生成了上下文和类文件。我需要使用我的上下文访问存储过程。在早期版本的entity framework中,在向导中选择存储过程对象并生成包含这些对象的edmx非常简单。然后,我可以通过实体框架公开的复杂类型对象访问存储过程。如何在实体框架核心中执行类似的操作。举个例子会有帮助吗?在EF Core和edmx文件中没有数据库优先的方法。相反,您必须使用Scaffo

我正在使用Visual Studio 2017实现Asp.Net核心Web API、实体框架核心、数据库优先方法。我已经成功地基于现有数据库生成了上下文和类文件。我需要使用我的上下文访问存储过程。在早期版本的entity framework中,在向导中选择存储过程对象并生成包含这些对象的edmx非常简单。然后,我可以通过实体框架公开的复杂类型对象访问存储过程。如何在实体框架核心中执行类似的操作。举个例子会有帮助吗?

在EF Core和edmx文件中没有数据库优先的方法。相反,您必须使用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
但是,这不会得到您的存储过程。它仍在工作中,跟踪问题

但是,要执行存储过程,请使用执行原始SQL查询的方法

e、 g

与参数一起使用

var productCategory= "Electronics";

var product = context.Products
    .FromSql("EXECUTE dbo.GetProductByCategory {0}", productCategory)
    .ToList();

执行原始SQL查询或存储过程有一定的限制。不能将其用于插入/更新/删除。如果要执行INSERT、UPDATE、DELETE查询,请使用EXECUTESQL命令

var categoryName = "Electronics";
dataContext.Database
           .ExecuteSqlCommand("dbo.InsertCategory @p0", categoryName);

我们在EF Core中用于执行存储过程以获取数据的解决方法是使用FromSql方法,您可以通过以下方式执行存储过程:

List<Employee> employees = dbcontext.Employee
                    .FromSql("GetAllEmployees").ToList();

如果希望结果集与任何已定义的对象相同,则在执行存储过程时,上述示例可以正常工作。但是,如果您想要一个不受支持的结果集,该怎么办?据EF Core 2的开发人员称,这是一项即将推出的功能,但现在已经有了一个简单的解决方案

创建要用于输出的模型。此模型将表示输出,而不是数据库中的表

namespace Example.EF.Model
{
    public class Sample
    {
        public int SampleID { get; set; }
        public string SampleName { get; set; }
    }
}
然后在您的上下文中添加一个新的DBSet和您的模型:

public virtual DbSet<Sample> Sample { get; set; }

我希望这对任何人都有帮助。

罗伊特/哈罗德·贾维尔/萨米提供的解决方案很有效。我想补充一点,您可以创建一个单独的EF6项目来为ResultSet生成C#类,然后将这些文件复制到您的EFCore项目中。如果更改存储过程,可以使用此处讨论的方法更新结果文件:

如果需要相应的typescript接口,可以安装此VS2017扩展typescript定义生成器:

仍然有一些复制操作,但是它没有手动创建类那么繁琐

编辑:有一个用于生成dbconext的VS2017扩展。它不执行存储过程,但它从VS project提供了一个右键单击菜单项,而不是命令行Scaffold DbContext。

My original post-

要调用存储过程并将结果放入EF Core中的模型列表中,我们必须遵循3个步骤

第1步。 您需要添加一个新类,就像您的实体类一样。其中应包含SP中所有列的属性。例如,如果SP返回两个名为
Id
Name
的列,则新类应为

public class MySPModel
{
    public int Id {get; set;}
    public string Name {get; set;}
}
第2步。

然后,您必须将一个
DbQuery
属性添加到SP的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
        ...
}
公共部分类声纳健康任命上下文:DbContext
{
公共虚拟数据库集预订{get;set;}//现有数据库集
...
公共虚拟数据库查询MySP{get;set;}//新数据库查询
...
}
第3步。

现在,您可以从DBContext调用SP并从中获取结果

var result = await _context.Query<MySPModel>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();
var result=await\u context.Query().AsNoTracking().FromSql(string.Format(“EXEC{0}{1}”,functionName,parameter)).toListSync();
我使用的是通用的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();
}
//
///执行函数。使用此函数时要格外小心,因为存在SQL注入的风险
/// 
公共异步任务ExecuteFunction(字符串函数名,字符串参数),其中T:class
{
返回wait{u context.Query().AsNoTracking().FromSql(string.Format(“EXEC{0}{1}”,functionName,parameter)).toListSync();
}

希望这将有助于某人

您可以将ADO.NET用于DbContextAng示例可能与第227行重复这很有帮助?在运行Scaffold DbContext System.ArgumentNullException后,我发现以下错误:值不能为null。参数名称:ContentRootPath这样做,每当我们使用EF生成模型时,我们每次都需要手动添加dbset?您可以使用分部类将它们放在不同的文件中,以使其更简单。嘿@Sami,您能提供分部类示例吗?
EXEC ReturnAllSamples{id},{startdate},{enddate}
将生成不带参数的sql,并且可以接受sql注入。当您试图以这种方式执行过程时,NETCore会给出一条非常彻底的警告消息。最好使用被接受的答案是
.FromSql(“EXECUTE dbo.GetProductByCategory{0}”,productCategory)
@SantiagoTrejo,我想他的意思是你可以创建你的DbContext的一部分(它们生成为partials)并在那里添加你的DbSet。这样,如果重新生成上下文,就不会丢失部分。如果SP使用join从多个表返回值,那么这将失败,那么我们应该使用什么方法呢。直到ef core拥有存储过程支持。
public class MySPModel
{
    public int Id {get; set;}
    public string Name {get; set;}
}
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
        ...
}
var result = await _context.Query<MySPModel>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();
/// <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();
}