Unterstützt Entity Framework Code First gespeicherte Prozeduren?


112

Ich habe mehrere Präsentationen von EF Code First gesehen und nicht gesehen, wie EFCF mit gespeicherten Prozeduren funktioniert.

Wie kann ich eine Methode deklarieren, die sp verwendet? Kann ich eine Entität an eine Methode übergeben, die sp aufruft, ohne Entitätseigenschaften manuell sp-Parametern zuzuordnen?

Was passiert auch, wenn ich mein Modell ändere? Würde es meine SP fallen lassen, während die Tabelle aus dem Modell neu erstellt wird? Und was ist mit Auslösern?

Wenn diese Dinge nicht unterstützt werden, gibt es Pläne, sie in Zukunft zu unterstützen?


5
Die EF-Roadmap weist darauf hin, dass EF 6 gespeicherte Prozeduren und Funktionen für Code First unterstützt. entityframework.codeplex.com/wikipage?title=Roadmap
frennky

Antworten:


66

BEARBEITEN: Meine ursprüngliche Antwort für EF4.1 (unten) ist jetzt veraltet. Bitte lesen Sie die Antwort unten von Diego Vega (der im EF-Team von Microsoft arbeitet)!


@gsharp und Shawn Mclean: Woher bekommen Sie diese Informationen? Haben Sie noch keinen Zugriff auf den zugrunde liegenden ObjectContext?

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

Ersetzen Sie die "select" -Anweisung durch einen gespeicherten Prozess, und los geht's.

Was Ihre andere Frage betrifft: Ja, leider werden Ihre SPs überlastet. Möglicherweise müssen Sie die Anweisungen "CREATE PROCEDURE" in Ihren Code einfügen.

Für EF 4.2:

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

Vielen Dank. Könnten Sie mich auf einige Links verweisen, die weitere Informationen zu diesem Thema enthalten?
Frennky

1
Sie möchten die drei Execute-Funktionen für das ObjectContext-Objekt nachschlagen (ExecuteStoreQuery, ExecuteFunction und ExecuteStoreCommand).
Anon

Ich habe die Frage falsch verstanden. Ich dachte, dass er SPs auf Codebasis erstellen möchte.
Gsharp

Sie können Context.OnModelCreating überschreiben und benutzerdefinierte Logik hinzufügen, um Datenbankelemente wie gespeicherte Prozesse relativ einfach über Code zu erstellen. Nicht ideal, aber zur Not reicht es aus.
Rick Strahl

Sie benötigen die IObjectContextAdapter-Besetzung nicht. Der DbContext kann sps oder benutzerdefinierte SQL-Anweisungen mithilfe des integrierten Datenbankobjekts verarbeiten: context.Database.SqlQuery <Dummy> ("sp_GetDummy");
Steven K.

50

Update: Ab EF6 unterstützt EF Code First die Zuordnung gespeicherter Prozeduren für Einfügungen, Aktualisierungen und Löschungen. Sie können die Zuordnung gespeicherter Prozeduren während der Modellerstellung mithilfe der MapToStoredProcedures-Methode angeben. Wir unterstützen auch das automatische Gerüst für grundlegende gespeicherte Prozeduren für diese Vorgänge. Siehe die Funktionsspezifikation hier .

Ursprüngliche Antwort: In der ersten Version wird weder die Zuordnung gespeicherter Prozeduren im Modell in Code-First unterstützt, noch können wir automatisch gespeicherte Prozeduren für CRUD-Operationen aus Ihren Typen generieren. Dies sind Funktionen, die wir in Zukunft hinzufügen möchten.

Wie in diesem Thread erwähnt, ist es möglich, auf ObjectContext zurückzugreifen, aber DbContext bietet auch nette APIs zum Ausführen nativer SQL-Abfragen und -Befehle (z. B. DbSet.SqlQuery, DbContext.Database.SqlQuery und DbContext.Database.ExecuteSqlCommand). Die verschiedenen SqlQuery-Versionen verfügen über dieselbe grundlegende Materialisierungsfunktionalität wie EF4 (wie ExecuteStoreQuery: http://msdn.microsoft.com/en-us/library/dd487208.aspx ).

Hoffe das hilft.


6
Übrigens habe ich vor einigen Tagen einen Blog-Beitrag geschrieben, in dem beschrieben wird, wie diese Methoden zum Aufrufen gespeicherter Prozeduren verwendet werden, auch gespeicherter Prozeduren mit Ausgabeparametern: blogs.msdn.com/b/diego/archive/2012/01/10/… .
Divega

3
Ende 2013 befindet sich EF6 noch in der Entwicklung. Ich warte drei Jahre, um die Unterstützung für Sprocs zu verbessern, seufz.
DOK

1
@divega Gibt es eine stark typisierte Unterstützung für die Auswahl von Werten aus einer gespeicherten Prozedur - dieser Code-First-Ansatz scheint spezifisch für die Verwaltung der Objektlebensdauer zu sein? Insbesondere für komplexe Suchvorgänge wird eine gespeicherte spFooSearch-Prozedur mit einem TotalRows-Ausgabeparameter verwendet.
John Zabroski

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

Eine typsicherere Lösung wäre:

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

Die Verwendung dieser Klasse ist:

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

var result = DbContext.Database.ExecuteStoredProcedure(testProcedureStoredProcedure);

Der Link ist nicht mehr aktiv, aber hier ist das Archiv: web.archive.org/web/20150430090848/http://www.lucbos.net/2012/…
Arturo Torres Sánchez

2

Für .NET Core (EntityFrameworkCore) konnte ich sie zum Laufen bringen.

Könnte nicht das ordentlichste sein, aber das funktioniert definitiv.

Die Migration zum Addieren der gespeicherten Prozedur sieht aus wie diese :

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

Ich könnte es dann mit folgendem Code aufrufen :

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

Später wurde versucht, einige der zugehörigen Daten abzurufen (eine bis viele Beziehungsdaten, z. B. Post-Inhalt), und der Blog kam mit dem gefüllten Post-Inhalt wie erwartet zurück.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.