【问题标题】:Does Entity Framework Code First support stored procedures?Entity Framework Code First 是否支持存储过程?
【发布时间】:2011-06-18 05:32:42
【问题描述】:

我看过几个 EF Code First 的演示文稿,但还没有看到 EFCF 如何处理存储过程。

我如何声明一个将使用一些 sp 的方法?我可以将实体传递给调用 sp 的方法,而无需手动将实体属性映射到 sp 参数吗?

另外,如果我更改模型会怎样?从模型重新创建表时它会删除我的 sp 吗?那么触发器呢?

如果这些东西不被支持,未来是否有计划支持它们?

【问题讨论】:

标签: c# entity-framework stored-procedures code-first


【解决方案1】:

更新:从 EF6 开始,EF Code First 支持插入、更新和删除的存储过程映射。您可以在模型创建期间使用 MapToStoredProcedures 方法指定存储过程映射。我们还支持这些操作的基本存储过程的自动脚手架。请参阅功能规范here

原答案: 在第一个版本中,我们将不支持在 Code-First 中的模型中映射存储过程,我们也将无法根据您的类型为 CRUD 操作自动生成存储过程。这些是我们希望在未来添加的功能。

正如该线程中提到的,可以回退到 ObjectContext,但 DbContext 还提供了很好的 API 来执行本机 SQL 查询和命令(例如 DbSet.SqlQuery、DbContext.Database.SqlQuery 和 DbContext.Database.ExecuteSqlCommand) .不同的 SqlQuery 版本具有与 EF4 相同的基本实现功能(如 ExecuteStoreQuery:http://msdn.microsoft.com/en-us/library/dd487208.aspx)。

希望这会有所帮助。

【讨论】:

  • 顺便说一句,我前几天写了一篇博文,详细介绍了如何使用这些方法来调用存储过程,甚至是带有输出参数的存储过程:blogs.msdn.com/b/diego/archive/2012/01/10/…
  • 2013 年末,EF6 仍在开发中。等待三年只是为了改进对存储过程的支持,叹息。
  • @divega 是否有强类型支持只从存储过程中选择值 - 这种代码优先方法似乎特定于管理对象生命周期?具体来说,对于复杂搜索,使用带有 TotalRows 输出参数的 spFooSearch 存储过程。
【解决方案2】:

对于 .NET Core (EntityFrameworkCore),我已经能够让它们正常工作。

可能不是最整洁的,但这绝对有效。

添加存储过程的迁移看起来像this

using Microsoft.EntityFrameworkCore.Migrations;
using System.Text;

namespace EFGetStarted.AspNetCore.NewDb.Migrations
{
    public partial class StoredProcedureTest : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("CREATE PROCEDURE GetBlogForAuthorName");
            sb.AppendLine("@authorSearch varchar(100)");
            sb.AppendLine("AS");
            sb.AppendLine("BEGIN");
            sb.AppendLine("-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.");
            sb.AppendLine("SET NOCOUNT ON;");
            sb.AppendLine("SELECT  Distinct Blogs.BlogId, Blogs.Url");
            sb.AppendLine("FROM Blogs INNER JOIN");
            sb.AppendLine("Posts ON Blogs.BlogId = Posts.BlogId INNER JOIN");
            sb.AppendLine("PostsAuthors ON Posts.PostId = PostsAuthors.PostId Inner JOIN");
            sb.AppendLine("Authors on PostsAuthors.AuthorId = Authors.AuthorId");
            sb.AppendLine("Where Authors.[Name] like '%' + @authorSearch + '%'");
            sb.AppendLine("END");

            migrationBuilder.Sql(sb.ToString());
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql("DROP PROCEDURE GetBlogForAuthorName");
        }
    }
}

然后我可以使用following 代码调用它:

var blogs = _context.Blogs.FromSql("exec GetBlogForAuthorName @p0", "rod").Distinct();

后来尝试获取一些相关数据(一对多关系数据,例如帖子内容),并且博客返回了预期的填充帖子内容。

【讨论】:

    【解决方案3】:

    一个更安全的解决方案是这样的:

    http://strugglesofacoder.blogspot.be/2012/03/calling-stored-procedure-with-entity.html

    这个类的用法是:

    var testProcedureStoredProcedure = new TestProcedureStoredProcedure() { Iets = 5, NogIets = true };
    
    var result = DbContext.Database.ExecuteStoredProcedure(testProcedureStoredProcedure);
    

    【讨论】:

    【解决方案4】:

    编辑:我对 EF4.1(下)的原始答案现在已经过时了。请参阅the answer below from Diego Vega(在 Microsoft EF 团队工作)!


    @gsharp 和 Shawn Mclean:你从哪里得到这些信息?难道你还不能访问底层的 ObjectContext 吗?

    IEnumerable<Customer> customers = 
        ((IObjectContextAdapter)this)
        .ObjectContext.ExecuteStoreQuery<Customer>("select * from customers");
    

    用存储过程替换“select”语句,然后就可以了。

    至于您的另一个问题:是的,不幸的是,您的 s.p. 会被破坏。您可能需要在代码中添加“CREATE PROCEDURE”语句。

    对于 EF 4.2:

    var customers = context.Database.SqlQuery<Customer>("select * from customers")
    

    【讨论】:

    • 谢谢。您能否指出一些包含有关此主题的更多信息的链接。
    • 您需要查找 ObjectContext 对象上的三个 Execute 函数(ExecuteStoreQuery、ExecuteFunction 和 ExecuteStoreCommand)。
    • 我误解了这个问题。我在想他想在代码优先的基础上创建 SP。
    • 您可以覆盖 Context.OnModelCreating 并添加自定义逻辑以通过代码相当轻松地创建存储过程等数据库项目。不理想,但在紧要关头它会成功。
    • 您不需要 IObjectContextAdapter 演员表。 DbContext 可以使用内置的数据库对象处理 sp 或自定义 SQL 语句:context.Database.SqlQuery("sp_GetDummy");
    【解决方案5】:
        public IList<Product> GetProductsByCategoryId(int categoryId)
        {
            IList<Product> products;
    
            using (var context = new NorthwindData())
            {
                SqlParameter categoryParam = new SqlParameter("@categoryID", categoryId);
                products = context.Database.SqlQuery<Product>("Products_GetByCategoryID @categoryID", categoryParam).ToList();
            }
    
            return products;
        }
    
        public Product GetProductById(int productId)
        {
            Product product = null;
    
            using (var context = new NorthwindData())
            {
                SqlParameter idParameter = new SqlParameter("@productId", productId);
                product = context.Database.SqlQuery<Product>("Product_GetByID @productId", idParameter).FirstOrDefault();
            }
    
            return product;
        }
    

    【讨论】:

      猜你喜欢
      • 2011-06-27
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 1970-01-01
      • 2011-06-06
      • 2016-08-04
      • 1970-01-01
      相关资源
      最近更新 更多