توسعه دهندگان دات نت اغلب نیاز به فراخوانی رویه ذخیره شده پایگاه داده (SP) از لایه سرور C# خود دارند. مایکروسافت هسته چارچوب نهاد (EF). می تواند برای نقشه برداری یا وارد کردن SP ها به عنوان توابع استفاده شود، اما، متأسفانه، EF Core به طور بومی از بازیابی نتایج پیچیده از رویه های ذخیره شده پشتیبانی نمی کند. این به دلیل محدودیتهای موجود در راهحل خارج از جعبه EF Core است که:
- نتیجه یک رویه ذخیره شده را به یک محدود کنید
Entity
نوع - نمی توان یک نوع پیچیده را در پاسخ به a برگرداند
JOIN
فرمان - عملیات ایجاد، بهروزرسانی و حذف را غیرقابل دسترس کنید.
ما می توانیم با استفاده از C#، .NET، Microsoft SQL Server و EF Core این محدودیت ها را دور بزنیم. این راه حل را می توان با هر پایگاه داده با پشتیبانی دات نت یا زبان دات نت که از EF Core پشتیبانی می کند استفاده کرد، مشروط بر اینکه کد ابزار به آن زبان ترجمه شده باشد. ما به یک نمونه رویه ذخیره شده نگاه می کنیم تا ببینیم چگونه چند تنظیم ساده می تواند بر محدودیت های EF Core غلبه کند.
یک روش ذخیره شده فرضی با یک نتیجه پیچیده
در نظر بگیریم GetEmployeesWithDepartment
، یک رویه ذخیره شده که یک نتیجه پیچیده حاوی اطلاعات از دو جدول پایگاه داده مرتبط را برمی گرداند، Employee
و Department
:
این Employee
جدول خود را از طریق a ارجاع می دهد کلید خارجی از آن ManagerId
رشته. همچنین به Department
جدول از Employee.DepartmentId
فیلد متصل به Department
جدول Id
ستون روابط ترتیبی بین این جداول عبارتند از:
Relationships = Employee(1) : Department(1) and Department(1) : Employees(N)
حالا بیایید نگاه کنیم GetEmployeesWithDepartment
، یک SP که an را برمی گرداند Employee
ردیف جدول مطابق با پارامتر ورودی Employee.Id
. SP ما را برمی گرداند Id
ارزش و تمام اطلاعات مرتبط با آن، مانند کارمند Department
و Name
ارزش های:
CREATE OR ALTER PROCEDURE [dbo].[GetEmployeesWithDepartment]
@id INT
AS
BEGIN
SET NOCOUNT ON;
SELECT [E].*, [D].[Name] AS [Department]
FROM [dbo].[Employee] [E]
INNER JOIN [dbo].[Department] [D] ON [E].[DepartmentId] = [D].[Id]
WHERE [E].[Id] >= @id
END
فرض کنید میخواهیم بخش مرتبط با اولین کارمند فهرست شده در a را تعیین کنیم پایگاه داده تست ساده (در مثال ما، اولین کارمند لیست شده جان در مهندسی است). ما می خواهیم این SP را از کد C# خود اجرا کنیم، بنابراین اجازه دهید EF Core را برای پشتیبانی از تماس پیکربندی کنیم. GetEmployeesWithDepartment
به عنوان یک SP پارامتر شده.
توجه: قبل از ادامه، پایگاه داده خود را داربست کنید با استفاده از Scaffold-DbContext
دستور در کنسول Package Manager یا dotnet ef dbcontext scaffold
دستور در NET Core CLI.
مرحله 1: یک مدل مجموعه نتایج ذخیره شده رویه ایجاد کنید
ابتدا یک فایل به نام ایجاد می کنیم GetEmployeesWithDepartment_Result.cs
و ساختار را برای نوع بازگشت پیچیده ما تعریف کنید:
public class GetEmployeesWithDepartment_Result
{
public int Id { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
public int? ManagerId { get; set; }
public int Salary { get; set; }
public decimal? Bonus { get; set; }
public string Department { get; set; }
}
با استفاده از Microsoft SQL Server به عنوان سرور پایگاه داده، میتوانیم به طور صریح انواع ستونهای نتیجه SP را با اجرای sp_describe_first_result_set
دستور:
EXEC sp_describe_first_result_set N'[dbo].[GetEmployeesWithDepartment]'
این دستور نشان می دهد ستون های رویه ذخیره شده و لیست انواع مرتبط با تعریف نوع نتیجه، ما به سمت به روز رسانی خود حرکت می کنیم مدل EF.
مرحله 2: شامل مدل در DbContext
فایل
ما آماده هستیم تا مدل نتیجه را در هسته EF برنامه خود بگنجانیم DbContext
فایل. EF یک رویکرد ظریف برای گسترش مدل داده یک برنامه ارائه می دهد. چنین یک برنامه افزودنی پشتیبانی می شود با کلاس های جزئی و – به طور خاص – با استفاده از یک OnModelCreatingPartial
روش. برای اینکه ابزارهای داربست EF Core کد سفارشی ما را تغییر ندهند، مدل نتیجه خود را به EFCoreSPContext.SP.cs
، یک کلاس C# جزئی:
using EFCoreSP.Data.SPs;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
namespace EFCoreSP.Data
{
public partial class EFCoreSPContext : DbContext
{
public virtual DbSet<GetEmployeesWithDepartment_Result>
GetEmployeesWithDepartment_Results { get; set; }
// We’ll add subsequent changes here
}
}
در اینجا چگونه است EFCoreSPContext.SP.cs
به داخل نگاه می کند مخزن ما. اکنون باید کدی را اضافه کنیم که کلید اصلی مدل ما را مشخص کند، در صورت وجود.
مرحله 3: کلید مدل را مشخص کنید
با پیکربندی مدل خود در یک نشان میدهیم که آیا مجموعه نتایج SP ما یک مقدار کلیدی دارد یا خیر OnModelCreatingPartial
روش در ما EFCoreSPContext
تعریف.
اگر مجموعه نتایج ما دارای یک مقدار کلیدی باشد، از آن استفاده می کنیم HasKey
روشی برای شناسایی صریح ویژگی مرتبط با آن مقدار کلیدی:
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<GetEmployeesWithDepartment_Result>(entity =>
entity.HasKey(e => e.Id));
}
اگر موجودیت ما هیچ مقدار کلیدی نداشته باشد، از آن استفاده می کنیم HasNoKey
روش در عوض:
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<GetEmployeesWithDepartment_Result>(entity =>
entity.HasNoKey());
}
تعریف مدل ما اکنون کامل شده است. ما آماده ایم با SP تماس گرفته و داده های کارمند نمونه خود را بازیابی کنیم.
فراخوانی مراحل ذخیره شده پیچیده: آسان به عنوان 1-2-3
برای ساده کردن فراخوانی SP خود، یک روش عمومی دیگر را به آن اضافه می کنیم EFCoreSPContext
فایل. تعریف روش این را می پذیرد Employee.Id
ارزش ارائه شده، از آن عبور می کند Id
به SP، و نتایج پیچیده تولید شده را به عنوان یک لیست بازیابی می کند:
public IEnumerable<GetEmployeesWithDepartment_Result>
SP_GetEmployeesWithDepartment(int id)
{
return this.GetEmployeesWithDepartment_Results
.FromSqlInterpolated($"[dbo].[GetEmployeesWithDepartment] {id}")
.ToArray();
}
ما DbContext
فایل اکنون آماده فراخوانی یک رویه ذخیره شده و برگرداندن یک مجموعه نتیجه نوع پیچیده است و ما کد کامل است. با بازگشت به پرس و جوی مثال خود، می توانیم از یک دستور ساده برای برگرداندن بخش و سایر داده های مرتبط با اولین کارمند در پایگاه داده خود استفاده کنیم:
var employees = dbContext.SP_GetEmployeesWithDepartment(1);
ما یک راه حل ساده و در عین حال هوشمندانه و قدرتمند را برای بازگرداندن یک موجودیت غیر پایگاه داده از رویه ذخیره شده اعمال کردیم. این رویکرد مستلزم خطوط نسبتا کمی از کد پشتیبانی است و هنگام استفاده از EF Core برای بازیابی نتایج پیچیده، سود قابل توجهی را به همراه دارد.
تیم تحریریه وبلاگ مهندسی تاپتال از شما تشکر می کند الکساندر اسکوگورف برای بررسی محتوای فنی و نمونه کد ارائه شده در این مقاله.