Entity Framework Code First รองรับกระบวนงานที่จัดเก็บไว้หรือไม่


112

ฉันได้ดูการนำเสนอ EF Code First หลายครั้งแล้วและยังไม่เห็นว่า EFCF ทำงานร่วมกับขั้นตอนการจัดเก็บอย่างไร

ฉันจะประกาศวิธีการที่จะใช้ sp บางตัวได้อย่างไร? ฉันสามารถส่งเอนทิตีไปยังเมธอดที่เรียกใช้ sp โดยไม่ต้องแมปคุณสมบัติเอนทิตีกับพารามิเตอร์ sp ด้วยตนเองได้หรือไม่

นอกจากนี้จะเกิดอะไรขึ้นถ้าฉันเปลี่ยนรุ่นของฉัน? มันจะลด sp ของฉันในขณะที่สร้างตารางจากโมเดลใหม่หรือไม่? แล้วทริกเกอร์ล่ะ?

หากสิ่งเหล่านี้ไม่ได้รับการสนับสนุนมีแผนรองรับในอนาคตหรือไม่?


5
แผนงานของ EF ชี้ให้เห็นว่า EF 6 จะรองรับขั้นตอนและฟังก์ชันที่จัดเก็บไว้สำหรับ Code First entityframework.codeplex.com/wikipage?title=Roadmap
frennky

ดูเพิ่มเติมที่: stackoverflow.com/questions/4873607/…
Nathan Koop

คำตอบ:


66

แก้ไข:คำตอบเดิมของฉันสำหรับ EF4.1 (ด้านล่าง) ล้าสมัยแล้ว โปรดดูคำตอบด้านล่างจาก Diego Vega (ซึ่งทำงานในทีม EF ที่ Microsoft)!


@gsharp และ Shawn Mclean: คุณหาข้อมูลนี้มาจากไหน? คุณยังไม่สามารถเข้าถึง ObjectContext พื้นฐานได้หรือไม่?

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

แทนที่คำสั่ง "select" ด้วย proc ที่เก็บไว้และไปที่นั่น

สำหรับคำถามอื่น ๆ ของคุณ: ใช่โชคไม่ดีที่ sp ของคุณจะคลอน คุณอาจต้องเพิ่มคำสั่ง "CREATE PROCEDURE" ในโค้ดของคุณ

สำหรับ EF 4.2:

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

ขอบคุณ คุณช่วยชี้ให้ฉันดูลิงก์ที่มีข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ไหม
frennky

1
คุณจะต้องค้นหาฟังก์ชัน Execute สามฟังก์ชันบนวัตถุ ObjectContext (ExecuteStoreQuery, ExecuteFunction และ ExecuteStoreCommand)
anon

ฉันเข้าใจคำถามผิด ฉันคิดว่าเขาต้องการสร้าง SP บนพื้นฐานของรหัสก่อน
gsharp

คุณสามารถแทนที่ Context OnModelCreating และเพิ่มตรรกะที่กำหนดเองเพื่อสร้างรายการฐานข้อมูลเช่น procs ที่เก็บไว้ผ่านรหัสได้ค่อนข้างง่าย ไม่เหมาะ แต่ในการหยิกมันจะทำเคล็ดลับ
Rick Strahl

คุณไม่จำเป็นต้องใช้ IObjectContextAdapter DbContext สามารถจัดการ sp หรือคำสั่ง SQL แบบกำหนดเองโดยใช้อ็อบเจ็กต์ฐานข้อมูลในตัว: context.Database.SqlQuery <Dummy> ("sp_GetDummy");
Steven 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/en-us/library/dd487208.aspx )

หวังว่านี่จะช่วยได้


6
BTW ผมเขียนบล็อกโพสต์ไม่กี่วันที่ผ่านมาว่ารายละเอียดวิธีการใช้วิธีการเหล่านี้จะก่อให้เกิดการจัดเก็บแม้กระทั่งวิธีการจัดเก็บที่มีพารามิเตอร์ที่ส่งออก: blogs.msdn.com/b/diego/archive/2012/01/10/...
divega

3
ปลายปี 2013 EF6 ยังอยู่ระหว่างการพัฒนา รอสามปีเพื่อปรับปรุงการรองรับ sprocs ถอนหายใจ
DOK

1
@divega มีการรองรับการพิมพ์อย่างมากสำหรับการเลือกค่าจากโพรซีเดอร์ที่เก็บไว้หรือไม่ - วิธีการโค้ดแรกนี้ดูเหมือนเฉพาะสำหรับการจัดการอายุการใช้งานของวัตถุหรือไม่ โดยเฉพาะสำหรับการค้นหาที่ซับซ้อนโดยใช้โพรซีเดอร์ที่เก็บ spFooSearch พร้อมพารามิเตอร์เอาต์พุต TotalRows
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

วิธีแก้ปัญหาที่ปลอดภัยกว่าประเภทนี้คือ:

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

ลิงก์ไม่สามารถใช้งานได้อีกต่อไป แต่นี่คือที่เก็บถาวร: web.archive.org/web/20150430090848/http://www.lucbos.net/2012/…
Arturo Torres Sánchez

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

ต่อมาได้พยายามรับข้อมูลที่เกี่ยวข้องบางส่วน (ข้อมูลความสัมพันธ์แบบหนึ่งต่อหลายข้อมูลเช่นโพสต์เนื้อหา) และบล็อกก็กลับมาพร้อมกับเนื้อหาโพสต์ที่เต็มไปด้วยข้อมูลตามที่เปิดเผย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.