【问题标题】:How to call Stored Procedures with EntityFramework?如何使用 EntityFramework 调用存储过程?
【发布时间】:2012-12-25 05:50:33
【问题描述】:

我从 MySQL 数据库生成了一个 EF4 模型,并包含了 StoredProcedures 和 Tables。

我知道如何对 EF 进行常规的插入/更新/获取/删除操作,但我找不到我的 StoredProcedures。

这正是我所希望的:

using (Entities context = new Entities())
{
    context.MyStoreadProcedure(Parameters); 
}

编辑1:

这是没有 EF 时的样子:

sqlStr = "CALL updateGame(?,?,?,?,?,?,?)";

commandObj = new OdbcCommand(sqlStr, mainConnection);
commandObj.Parameters.Add("@id,", OdbcType.Int).Value = inGame.id;
commandObj.Parameters.Add("@name", OdbcType.VarChar, 255).Value = inGame.name;
commandObj.Parameters.Add("@description", OdbcType.Text).Value = ""; //inGame.description;
commandObj.Parameters.Add("@yearPublished", OdbcType.DateTime).Value = inGame.yearPublished;
commandObj.Parameters.Add("@minPlayers", OdbcType.Int).Value = inGame.minPlayers;
commandObj.Parameters.Add("@maxPlayers", OdbcType.Int).Value = inGame.maxPlayers;
commandObj.Parameters.Add("@playingTime", OdbcType.VarChar, 127).Value = inGame.playingTime;    

return Convert.ToInt32(executeScaler(commandObj));

PS。如果需要,我可以更改 EF 版本

编辑1:

CREATE DEFINER=`106228`@`%` PROCEDURE `updateGame`(
    inId INT,
    inName VARCHAR(255),
    inDescription TEXT,
    inYearPublished DATETIME,
    inMinPlayers INT,
    inMaxPlayers INT,
    inPlayingTime VARCHAR(127)
)

【问题讨论】:

    标签: c# mysql entity-framework stored-procedures


    【解决方案1】:

    一种方法是使用 DbContext 之外的 Database 属性:

    SqlParameter param1 = new SqlParameter("@firstName", "Frank");
    SqlParameter  param2 = new SqlParameter("@lastName", "Borland");
    context.Database.ExecuteSqlCommand("sp_MyStoredProc @firstName, @lastName", 
                                  param1, param2);
    

    EF5 绝对支持。

    【讨论】:

    • 我不明白,为什么要硬编码 SP 名称?我在生成模型时添加了它们?不应该只是作为方法存在于 Context 对象的某个地方吗?
    • 是的,如果你没有将它链接到你的模型并且你想要 raw 访问,这就是这样做的方法;)
    • 这只是将存储的过程作为非查询执行。它无法读取任何返回的表
    【解决方案2】:

    您已使用 SqlQuery 函数并指示实体映射结果。

    我发送一个示例来执行此操作:

    var oficio= new SqlParameter
    {
        ParameterName = "pOficio",
        Value = "0001"
    };
    
    using (var dc = new PCMContext())
    {
        return dc.Database
                 .SqlQuery<ProyectoReporte>("exec SP_GET_REPORTE @pOficio",
                                            oficio)
                 .ToList();
    }
    

    【讨论】:

    • 你必须声明你的ProyectoReporte 类来代表查询返回的结果表
    【解决方案3】:

    将存储过程导入模型后,您可以右键单击它(从模型浏览器中的Context.Store/Stored Procedures 部分),然后单击Add Function Import。如果你需要一个复杂的类型,你可以在那里创建它。

    【讨论】:

    • 试过了,但它没有生成带参数的方法?不知道如何输入参数?
    • 当程序有参数时,就会被添加。
    • 它适用于我,使用框架 4。你能显示该过程的创建语句吗? (仅带参数)
    • 所以,你没有什么奇怪的东西。它确实应该支持参数,我不确定为什么不支持。你能用一个只有几个参数的过程来试试,比如 3 个整数,看看它做了什么?
    • 我尝试添加一个只有一个参数但它不起作用
    【解决方案4】:

    基于 OP 的原始请求,能够像这样调用存储过程...

    using (Entities context = new Entities())
    {
        context.MyStoreadProcedure(Parameters); 
    }
    

    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)
        {
        }
    }
    

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

    【讨论】:

      【解决方案5】:

      基本上,您只需使用存储过程映射将过程映射到实体。

      映射后,您使用常规方法在 EF 中添加项目,它将使用您的存储过程。

      请参阅:This Link 了解演练。 结果将添加一个像这样的实体(实际上将使用您的存储过程)

      using (var ctx = new SchoolDBEntities())
              {
                  Student stud = new Student();
                  stud.StudentName = "New sp student";
                  stud.StandardId = 262;
      
                  ctx.Students.Add(stud);
                  ctx.SaveChanges();
              }
      

      【讨论】:

      • 尽管有所有答案,但这是 OP 正在寻找的唯一答案。
      【解决方案6】:

      这是我最近为具有 2008 SQL 数据库的数据可视化应用程序所做的。在这个例子中,我收到了一个从存储过程返回的列表:

      public List<CumulativeInstrumentsDataRow> GetCumulativeInstrumentLogs(RunLogFilter filter)
          {
              EFDbContext db = new EFDbContext();
              if (filter.SystemFullName == string.Empty)
              {
                  filter.SystemFullName = null;
              }
              if (filter.Reconciled == null)
              {
                  filter.Reconciled = 1;
              }
              string sql = GetRunLogFilterSQLString("[dbo].[rm_sp_GetCumulativeInstrumentLogs]", filter);
              return db.Database.SqlQuery<CumulativeInstrumentsDataRow>(sql).ToList();
          }
      

      然后在我的情况下这个扩展方法用于一些格式:

      public string GetRunLogFilterSQLString(string procedureName, RunLogFilter filter)
              {
                  return string.Format("EXEC {0} {1},{2}, {3}, {4}", procedureName, filter.SystemFullName == null ? "null" : "\'" + filter.SystemFullName + "\'", filter.MinimumDate == null ? "null" : "\'" + filter.MinimumDate.Value + "\'", filter.MaximumDate == null ? "null" : "\'" + filter.MaximumDate.Value + "\'", +filter.Reconciled == null ? "null" : "\'" + filter.Reconciled + "\'");
      
              }
      

      【讨论】:

      • 我不明白,为什么要硬编码 SP 名称?我在生成模型时添加了它们?不应该只是作为方法存在于 Context 对象的某个地方吗?
      【解决方案7】:

      这是一个使用实体框架查询 MySQL 过程的示例

      这是我在 MySQL 中存储过程的定义:

      CREATE PROCEDURE GetUpdatedAds (
          IN curChangeTracker BIGINT
          IN PageSize INT
      ) 
      BEGIN
         -- select some recored...
      END;
      

      这就是我使用实体框架查询它的方式:

       var curChangeTracker = new SqlParameter("@curChangeTracker", MySqlDbType.Int64).Value = 0;
       var pageSize = new SqlParameter("@PageSize", (MySqlDbType.Int64)).Value = 100;
      
       var res = _context.Database.SqlQuery<MyEntityType>($"call GetUpdatedAds({curChangeTracker}, {pageSize})");
      

      请注意,我使用C# String Interpolation 来构建我的查询字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-05
        • 2021-12-29
        • 2016-01-23
        相关资源
        最近更新 更多