在实体框架中使用存储过程

Posted

技术标签:

【中文标题】在实体框架中使用存储过程【英文标题】:using stored procedure in entity framework 【发布时间】:2014-01-25 01:32:09 【问题描述】:

我正在使用带有实体框架的 asp.net mvc 5 和 C#...我有函数的模型和域类...现在我需要使用存储过程...。我正在努力解决这个问题。

我首先关注现有数据库的代码,并且我已经在那里编写了存储过程。我的问题是如何在我的 Web 应用程序中调用该存储过程。

存储过程:

ALTER PROCEDURE [dbo].[GetFunctionByID](
    @FunctionId INT
)
AS
BEGIN
    SELECT * 
    FROM Functions As Fun
    WHERE Function_ID = @FunctionId
END

领域类:

 public class Functions
 
    public Functions()
    
    

    public int Function_ID  get; set; 
    public string Title  get; set; 
    public int Hierarchy_level  get; set; 

功能模型:

[Table("Functions")]
public class App_Functions

    public App_Functions()
    
    

    [Key]
    public int Function_ID  get; set; 

    [StringLength(50)]
    [Required]
    public string Title  get; set; 

    public int Hierarchy_level  get; set; 
    //public virtual ICollection<App_Controllers> App_Controllers  get; set; */

基本上下文:

public class BaseContext<TContext> : DbContext where TContext : DbContext

    static BaseContext()
    
        Database.SetInitializer<TContext>(null);
    

    protected BaseContext()
        : base("name = ApplicationDbConnection")
     

函数上下文:

public class FunctionsContext : BaseContext<FunctionsContext>

    public DbSet<App_Functions> Functions  get; set; 

【问题讨论】:

【参考方案1】:

您需要创建一个包含所有存储过程属性的模型类,如下所示。 另外由于Entity Framework模型类需要主键,所以可以使用Guid创建一个假键。

public class GetFunctionByID

    [Key]
    public Guid? GetFunctionByID  get; set; 

    // All the other properties.

然后在您的DbContext 中注册GetFunctionByID 模型类。

public class FunctionsContext : BaseContext<FunctionsContext>

    public DbSet<App_Functions> Functions  get; set; 
    public DbSet<GetFunctionByID> GetFunctionByIds get;set;

当你调用你的存储过程时,请看下面:

var functionId = yourIdParameter;
var result =  db.Database.SqlQuery<GetFunctionByID>("GetFunctionByID @FunctionId", new SqlParameter("@FunctionId", functionId)).ToList());

【讨论】:

由于某种原因,我在调试时得到空值反对结果! 这对我不起作用。假密钥不能与实体类命名相同,因为它会导致错误“成员名称不能与其封闭类型相同”。如果我遗漏了密钥,我会在执行时收到模型验证错误,因为它没有密钥。如果我将假密钥命名为其他名称,它会尝试创建一个表。 如何在我的实体类中设置架构? ,我的SP不在dbo上。我收到错误消息:找不到存储过程 'xxx' @Lin 我收到错误消息,存储过程返回的result set 中不存在假密钥【参考方案2】:

导入存储过程后,可以创建存储过程的对象,传递函数的参数

using (var entity = new FunctionsContext())

   var DBdata = entity.GetFunctionByID(5).ToList<Functions>();

或者你也可以使用SqlQuery

using (var entity = new FunctionsContext())

    var Parameter = new SqlParameter 
                     ParameterName = "FunctionId",
                     Value = 5
            ;

    var DBdata = entity.Database.SqlQuery<Course>("exec GetFunctionByID @FunctionId ", Parameter).ToList<Functions>();

【讨论】:

【参考方案3】:

您可以使用SqlQuery 调用存储过程(参见here)

// Prepare the query
var query = context.Functions.SqlQuery(
    "EXEC [dbo].[GetFunctionByID] @p1", 
    new SqlParameter("p1", 200));

// add NoTracking() if required

// Fetch the results
var result = query.ToList();

【讨论】:

这是否意味着我不需要在 dbcontext 中为每个存储过程和 dbset 创建模型?? @toxic 你把200改成数据库中某个值的id了吗? @toxic 您将需要一个 sp 用于每个表的每个 CRUD 操作。 EF6 大大改进了对实体和存储过程之间映射的支持see here 我知道并使用了 id 2,我在数据库表中有记录! 使用 EF6 你可以使用 context.Database.SqlQuery【参考方案4】:

// 将一些租户添加到上下文中,以便我们为过程返回一些内容! AddTenentsToContext(Context);

    // ACT
    // Get the results by calling the stored procedure from the context extention method 
    var results = Context.ExecuteStoredProcedure(procedure);

    // ASSERT
    Assert.AreEqual(expectedCount, results.Count);

【讨论】:

// ACT // 通过上下文扩展方法调用存储过程获取结果 var results = Context.ExecuteStoredProcedure(procedure); // ASSERT Assert.AreEqual(expectedCount, results.Count++); 如果您想更改某些内容,请不要添加评论;而是点击“编辑”,然后直接应用更改。【参考方案5】:

Mindless passenger 有一个项目,允许您从这样的实体框架调用存储过程......

using (testentities te = new testentities())

    //-------------------------------------------------------------
    // Simple stored proc
    //-------------------------------------------------------------
    var parms1 = new testone()  inparm = "abcd" ;
    var results1 = te.CallStoredProc<testone>(te.testoneproc, parms1);
    var r1 = results1.ToList<TestOneResultSet>();

...我正在研究一个stored procedure framework (here),您可以像下面显示的我的测试方法之一那样调用它...

[TestClass]
public class TenantDataBasedTests : BaseIntegrationTest

    [TestMethod]
    public void GetTenantForName_ReturnsOneRecord()
    
        // ARRANGE
        const int expectedCount = 1;
        const string expectedName = "Me";

        // Build the paraemeters object
        var parameters = new GetTenantForTenantNameParameters
        
            TenantName = expectedName
        ;

        // get an instance of the stored procedure passing the parameters
        var procedure = new GetTenantForTenantNameProcedure(parameters);

        // Initialise the procedure name and schema from procedure attributes
        procedure.InitializeFromAttributes();

        // Add some tenants to context so we have something for the procedure to return!
        AddTenentsToContext(Context);

        // ACT
        // Get the results by calling the stored procedure from the context extention method 
        var results = Context.ExecuteStoredProcedure(procedure);

        // ASSERT
        Assert.AreEqual(expectedCount, results.Count);
    


internal class GetTenantForTenantNameParameters

    [Name("TenantName")]
    [Size(100)]
    [ParameterDbType(SqlDbType.VarChar)]
    public string TenantName  get; set; 


[Schema("app")]
[Name("Tenant_GetForTenantName")]
internal class GetTenantForTenantNameProcedure
    : StoredProcedureBase<TenantResultRow, GetTenantForTenantNameParameters>

    public GetTenantForTenantNameProcedure(
        GetTenantForTenantNameParameters parameters)
        : base(parameters)
    
    

如果这两种方法中的任何一种都好?

【讨论】:

【参考方案6】:

简单。只需实例化您的实体,将其设置为一个对象并将其传递给您的控制器中的视图。

实体

VehicleInfoEntities db = new VehicleInfoEntities();

存储过程

dbo.prcGetMakes()

您可以在存储过程中的方括号 () 内添加任何参数

dbo.prcGetMakes("BMW")

控制器

public class HomeController : Controller

    VehicleInfoEntities db = new VehicleInfoEntities();

    public ActionResult Index()
    
        var makes = db.prcGetMakes(null);

        return View(makes);
    

【讨论】:

以上是关于在实体框架中使用存储过程的主要内容,如果未能解决你的问题,请参考以下文章

在实体框架中使用存储过程(代码优先)

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

如何在实体框架中定义存储过程(代码优先)?

如何使用实体框架在 oracle 包中调用存储过程?

在实体框架数据库优先方法中,如何从存储过程返回多个结果集?

实体框架中存储过程的返回值映射