Entity Framework Code First是否支持存储过程?


112

我已经看过EF Code First的一些演示,还没有看到EFCF如何与存储过程一起工作。

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

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

如果不支持这些功能,将来是否有计划支持它们?


5
EF路线图指出EF 6将支持Code First的存储过程和功能。entityframework.codeplex.com/wikipage?title=路线图
疯狂

Answers:


66

编辑:我对EF4.1(以下)的原始答案现在已过时。请查看以下来自迭戈·维加(Microsoft EF团队的工作人员)的答案


@gsharp和Shawn Mclean:您从哪里获得此信息?您仍然没有访问底层ObjectContext的权限吗?

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

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

至于您的其他问题:是的,很不幸,您的sp会崩溃。您可能需要在代码中添加“ CREATE PROCEDURE”语句。

对于EF 4.2:

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

谢谢。您能否指出一些指向该主题的链接?
2011年

1
您将要在ObjectContext对象上查找三个Execute函数(ExecuteStoreQuery,ExecuteFunction和ExecuteStoreCommand)。
匿名

我误解了这个问题。我当时以为他想先基于代码创建SP。
gsharp 2011年

您可以重写Context.OnModelCreating并添加自定义逻辑,以通过代码轻松地创建数据库项(如存储的proc)。虽然不理想,但关键时刻可以解决问题。
Rick Strahl

您不需要IObjectContextAdapter强制转换。DbContext可以使用内置的Database对象处理sp或自定义SQL语句:context.Database.SqlQuery <Dummy>(“ sp_GetDummy”);
史蒂文·K。

50

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

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

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

希望这可以帮助。


6
顺便说一句,我几天前写了一篇博客文章,详细介绍了如何使用这些方法来调用存储过程,甚至是带有输出参数的存储过程:blogs.msdn.com/b/diego/archive/2012/01/10/…
divega 2012年

3
2013年底,EF6仍在开发中。等待三年只是为了改善对存储过程的支持,叹了口气。
DOK

1
@divega是否存在仅从存储过程中选择值的强类型支持-这种代码优先方法似乎特定于管理对象生存期?具体来说,对于复杂的搜索,请使用带有TotalRows输出参数的spFooSearch存储过程。
约翰·扎布罗斯基

31
    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;
    }

8

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

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);


2

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

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

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

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");
        }
    }
}

然后可以使用以下代码来调用它:

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

后来尝试获取一些相关数据(一对多关系数据,例如Post内容),然后Blog带着预期的已填充Post内容返回。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.