فرض کنید Stored Procedure ی با چند مقدار برگشتی را میخواهیم در EF CodeFirst مورد استفاده قرار دهیم. برای مثال Stored Procedure زیر را در نظر بگیرید:
CREATE PROCEDURE [dbo].[GetAllBlogsAndPosts] AS SELECT * FROM dbo.Blogs SELECT * FROM dbo.Posts
Stord Procedure ی که توسط این دستور ساخته میشود تمام رکوردهای جدول Blogs و تمامی رکوردهای جدول Posts را واکشی کرده و به عنوان خروجی برمیگرداند (دو خروجی متفاوت). روش فراخوانی و استفاده از دادههای این StoredProcedure در EF CodeFirst به صورت زیر است :
تعریف دو کلاس مدل Blog و Post به ترتیب برای نگهداری اطلاعات وبلاگها و پستها در زیر آمده است. در ادامه نیز تعریف کلاس BloggingContext را مشاهده میکنید.
public class Blog { public int BlogId { get; set; } public string Name { get; set; } public virtual List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public virtual Blog Blog { get; set; } } public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } } using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Objects; namespace Sproc.Demo { class Program { static void Main(string[] args) { using (var db = new BloggingContext()) { db.Database.Initialize(force: false); var cmd = db.Database.Connection.CreateCommand(); cmd.CommandText = "[dbo].[GetAllBlogsAndPosts]"; try { // اجرای پروسیجر db.Database.Connection.Open(); var reader = cmd.ExecuteReader(); // خواند رکوردهای blogs var blogs = ((IObjectContextAdapter)db) .ObjectContext .Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly); foreach (var item in blogs) { Console.WriteLine(item.Name); } // پرش به نتایج بعدی (همان Posts) reader.NextResult(); var posts = ((IObjectContextAdapter)db) .ObjectContext .Translate<Post>(reader, "Posts", MergeOption.AppendOnly); foreach (var item in posts) { Console.WriteLine(item.Title); } } finally { db.Database.Connection.Close(); } } } }
در کدهای بالا ابتدا یک Connection به بانک اطلاعاتی باز میشود:
db.Database.Connection.Open();
و پس از آن نوبت به اجرای Stored Procedure میرسد:
var reader = cmd.ExecuteReader();
در کد بالا پس از اجرای Stored Procudure نتایج بدست آمده در یک reader ذخیره میشود. شئ reader از نوع DBDataReader میباشد. پس از اجرای Stored Procedure و دریافت نتایج و ذخیره سازی در شئی reader ، نوبت به جداسازی رکوردها میرسد. همانطور که در تعریف Stored procedure مشخص است این Stored Procedure دارای دو نوع خروجی از نوعهای Blog و Post میباشد و این دو نوع باید از هم جدا شوند.برای انجام این کار از متد Translate شئی Context استفاده میشود. این متد قابلیت کپی کردن نتایج موجود از یک شئی DBDataReader به یک شئی از نوع مدل را دارد. برای مثال :
var blogs = ((IObjectContextAdapter)db) .ObjectContext .Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly);
در کدهای بالا تمامی رکوردهایی از نوع Blog از شئی reader خوانده شده و پس از تبدیل به نوع Blog درون شئی Blogs ذخیره میشود.
پس از آن توسط حلقه foreach محتویات Blogs پیمایش شده و مقدار موجود در فیلد Name نمایش داده میشود.
foreach (var item in blogs) { Console.WriteLine(item.Name); }
با توجه به اینکه حاصل اجرای این Stored Procedure دو خروجی متفاوت بوده است ، پس از پیمایش رکوردهای Blogs باید به سراغ نتایج بعدی که همان رکوردهای Post میباشد برویم. برای اینکار از متد NextResult شئی reader استفاده میشود:
reader.NextResult();
در ادامه برای خواندن رکوردهایی از نوع Post نیز به همان روشی که برای Blog انجام شد عمل میشود.