111

I've watched several presentations of EF Code First and haven't seen how EFCF works with stored procedures.

How can I declare a method that will use some sp? Can I pass an entity to a method that calls sp without manually mapping entity properties to sp parameters?

Also, what happens if I change my model? Would it drop my sp while recreating table from model? And what about triggers?

If these things are not supported, are there any plans to support them in future?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
frennky
  • 12,581
  • 10
  • 47
  • 63
  • 5
    EF roadmap points that EF 6 will support stored procedures and functions for Code First. http://entityframework.codeplex.com/wikipage?title=Roadmap – frennky Jul 21 '12 at 10:25
  • See also: http://stackoverflow.com/questions/4873607/how-to-use-dbcontext-database-sqlquerytelementsql-params-with-stored-proced – Nathan Koop Aug 14 '12 at 20:49

5 Answers5

65

EDIT: My original answer for EF4.1 (below) is now out of date. Please see the answer below from Diego Vega (who works on the EF team at Microsoft)!


@gsharp and Shawn Mclean: Where are you getting this information? Don't you still have access to the underlying ObjectContext?

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

Replace the "select" statement with a stored proc, and there you go.

As for your other question: Yes, unfortunately your s.p.'s will get clobbered. You may need to add the "CREATE PROCEDURE" statements in your code.

For EF 4.2:

var customers = context.Database.SqlQuery<Customer>("select * from customers")
Community
  • 1
  • 1
anon
  • 4,578
  • 3
  • 35
  • 54
  • Thanks. Could you point me to some links that have more info about this subject. – frennky Jan 30 '11 at 21:25
  • 1
    You'll want to look up the three Execute functions on the ObjectContext object (ExecuteStoreQuery, ExecuteFunction, and ExecuteStoreCommand). – anon Jan 30 '11 at 22:01
  • I misunderstood the question. I was thinking that he want to create SP's ond a code first basis. – gsharp Jan 31 '11 at 10:31
  • You can override Context.OnModelCreating and add custom logic to create database items like stored procs via code fairly easily. Not ideal but in a pinch it'll do the trick. – Rick Strahl Mar 04 '11 at 21:17
  • You don't need the IObjectContextAdapter cast. The DbContext can handle sp's or custom SQL statements using the built in Database object: context.Database.SqlQuery("sp_GetDummy"); – Steven K. Mar 23 '11 at 18:50
  • What reply from Diego Vega? Edit: oh, apparently you meant "answer", not "reply" -- his name also doesn't appear on the page because his SO handle is "divega". -- Thanks. – BrainSlugs83 Jun 25 '15 at 21:21
  • Just a note, use context.Database.SqlQuery("EXEC sp_GetDummy"); for SQL Server..... and use context.Database.SqlQuery("CALL sp_GetDummy"); for MySQL. – Himalaya Garg Nov 04 '16 at 10:25
50

Update: From EF6 on, EF Code First does support stored procedure mapping for inserts, updates and deletes. You can specify stored procedure mapping during model creation using the MapToStoredProcedures method. We also support automatic scaffolding of basic stored procedures for those operations. See the feature specification here.

Original answer: We won't have support for mapping stored procedures in the model in Code-First in the first release, nor we will have a way to automatically generate stored procedures for CRUD operations from your types. These are features that we would like to add in the future.

As it was mentioned in this thread, it is possible to fall back to ObjectContext but DbContext also provides nice APIs to execute native SQL queries and commands (e.g. DbSet.SqlQuery, DbContext.Database.SqlQuery and DbContext.Database.ExecuteSqlCommand). The different SqlQuery versions have the same basic materialization functionality that exists in EF4 (like ExecuteStoreQuery: http://msdn.microsoft.com/en-us/library/dd487208.aspx).

Hope this helps.

Collin K
  • 15,277
  • 1
  • 27
  • 22
divega
  • 6,320
  • 1
  • 31
  • 31
  • 6
    BTW, I wrote a blog post a few days ago that details how to use these methods to invoke stored procedures, even stored procedures with output parameters: http://blogs.msdn.com/b/diego/archive/2012/01/10/how-to-execute-stored-procedures-sqlquery-in-the-dbcontext-api.aspx. – divega Jan 17 '12 at 08:46
  • 3
    Late 2013, EF6 is still in development. Waiting three years just to improve support for sprocs, sigh. – DOK Sep 24 '13 at 02:04
  • 1
    @divega Is there strongly typed support for just selecting values from a stored procedure - this code-first approach seems specific to managing object life-time? Specifically, for complex searches, using a spFooSearch stored procedure with a TotalRows output parameter. – John Zabroski May 20 '14 at 21:53
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;
    }
Mark
  • 531
  • 5
  • 5
8

A more type safe solution would be this:

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

The usage of this class is:

var testProcedureStoredProcedure = new TestProcedureStoredProcedure() { Iets = 5, NogIets = true };

var result = DbContext.Database.ExecuteStoredProcedure(testProcedureStoredProcedure);
Luc Bos
  • 1,722
  • 1
  • 13
  • 24
  • The link is no longer active, but here's the archive: http://web.archive.org/web/20150430090848/http://www.lucbos.net/2012/03/calling-stored-procedure-with-entity.html – Arturo Torres Sánchez Jan 26 '16 at 18:13
2

For .NET Core (EntityFrameworkCore), I have been able to get them working.

Might not be the neatest, but this definitely works.

The migration for adding the stored procedure looks like 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");
        }
    }
}

I could then call it with the following code:

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

Later tried getting some of the related data (one to many relationship data e.g. Post content) and the blog came back with the filled Post content as exptected.

Community
  • 1
  • 1
JsAndDotNet
  • 16,260
  • 18
  • 100
  • 123