Entity Framework Code First, saklı yordamları destekliyor mu?


112

EF Code First'ün birkaç sunumunu izledim ve EFCF'nin saklı yordamlarla nasıl çalıştığını görmedim.

Biraz sp kullanacak bir yöntemi nasıl bildirebilirim? Varlık özelliklerini sp parametrelerine el ile eşlemeden sp'yi çağıran bir yönteme bir varlığı iletebilir miyim?

Ayrıca modelimi değiştirirsem ne olur? Modelden tabloyu yeniden oluştururken sp'mi düşürür mü? Peki ya tetikleyiciler?

Bunlar desteklenmiyorsa, gelecekte onları desteklemeye yönelik herhangi bir plan var mı?


5
EF yol haritası, EF 6'nın Code First için depolanan prosedürleri ve işlevleri destekleyeceğini belirtir. entityframework.codeplex.com/wikipage?title=Roadmap
frennky

Yanıtlar:


66

DÜZENLEME: EF4.1 için orijinal cevabım (aşağıda) artık güncel değil. Lütfen Diego Vega'nın (Microsoft'ta EF ekibinde çalışan) aşağıdaki cevaba bakın !


@gsharp ve Shawn Mclean: Bu bilgiyi nereden alıyorsunuz? Hala temeldeki ObjectContext'e erişiminiz yok mu?

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

"Select" ifadesini depolanan bir işlemle değiştirin ve işte başlayın.

Diğer sorunuza gelince: Evet, maalesef sp'leriniz yıpranacak. Kodunuza "CREATE PROCEDURE" ifadelerini eklemeniz gerekebilir.

EF 4.2 için:

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

Teşekkürler. Bu konu hakkında daha fazla bilgi içeren bazı bağlantılara işaret edebilir misiniz?
çılgınnky

1
ObjectContext nesnesinde (ExecuteStoreQuery, ExecuteFunction ve ExecuteStoreCommand) üç Execute işlevine bakmak isteyeceksiniz.
anon

Soruyu yanlış anladım. SP'leri ilk olarak bir kod temelinde oluşturmak istediğini düşünüyordum.
gsharp

Context.OnModelCreating'i geçersiz kılabilir ve depolanmış procs gibi veritabanı öğelerini oldukça kolay bir şekilde kod aracılığıyla oluşturmak için özel mantık ekleyebilirsiniz. İdeal değil ama bir çimdikle hile yapacak.
Rick Strahl

IObjectContextAdapter dökümüne ihtiyacınız yoktur. DbContext, yerleşik Veritabanı nesnesini kullanarak sp'lerin veya özel SQL ifadelerini işleyebilir: context.Database.SqlQuery <Dummy> ("sp_GetDummy");
Steven K.

50

Güncelleme: EF6'dan itibaren EF Code First, eklemeler, güncellemeler ve silmeler için saklı yordam eşleştirmeyi destekler. MapToStoredProcedures yöntemini kullanarak model oluşturma sırasında saklı yordam eşlemesini belirtebilirsiniz. Ayrıca, bu işlemler için temel depolanan prosedürlerin otomatik olarak iskele yapılmasını da destekliyoruz. Özellik özelliklerine buradan bakın .

Orijinal yanıt: İlk sürümde Code-First'te modeldeki saklı yordamları eşleme desteğimiz olmayacak veya türlerinizden CRUD işlemleri için depolanan yordamları otomatik olarak oluşturmanın bir yolunu bulamayacağız. Bunlar, gelecekte eklemek istediğimiz özelliklerdir.

Bu iş parçacığında bahsedildiği gibi, ObjectContext'e geri dönmek mümkündür, ancak DbContext ayrıca yerel SQL sorgularını ve komutlarını yürütmek için güzel API'ler sağlar (örn. DbSet.SqlQuery, DbContext.Database.SqlQuery ve DbContext.Database.ExecuteSqlCommand). Farklı SqlQuery sürümleri, EF4'te bulunan aynı temel materyalleştirme işlevine sahiptir (ExecuteStoreQuery gibi: http://msdn.microsoft.com/en-us/library/dd487208.aspx ).

Bu yardımcı olur umarım.


6
BTW, birkaç gün önce bu yöntemlerin saklı yordamları, hatta çıktı parametreleriyle birlikte saklı yordamları çağırmak için nasıl kullanılacağını ayrıntılarıyla anlatan bir blog yazısı yazdım: blogs.msdn.com/b/diego/archive/2012/01/10/… .
divega

3
2013'ün sonlarında, EF6 hâlâ geliştirme aşamasındadır. Sadece dişliler için desteği geliştirmek için üç yıl bekliyorum, iç çekiyorum.
DOK

1
@divega Depolanan bir prosedürden yalnızca değerleri seçmek için güçlü bir şekilde yazılmış bir destek var mı - bu ilk kod yaklaşımı, nesne yaşam süresini yönetmeye özgü görünüyor? Özellikle karmaşık aramalar için, bir TotalRows çıktı parametresiyle bir spFooSearch saklı yordamı kullanarak.
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

Daha güvenli bir çözüm şu olabilir:

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

Bu sınıfın kullanımı:

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

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


2

.NET Core (EntityFrameworkCore) için, onları çalıştırmayı başardım.

En temiz olmayabilir, ama bu kesinlikle işe yarıyor.

Gibi saklı yordam görünüyor eklemek için göç bu :

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

Daha sonra aşağıdaki kodla arayabilirim :

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

Daha sonra ilgili verilerden bazılarını almayı denedi (bir ila birçok ilişki verisi, örn. Gönderi içeriği) ve blog, beklendiği gibi doldurulmuş Gönderi içeriğiyle geri geldi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.