【问题标题】: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; }
}

【问题讨论】:

    标签: asp.net-mvc entity-framework stored-procedures repository-pattern


    【解决方案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);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-06-25
          • 1970-01-01
          • 1970-01-01
          • 2014-07-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多