تکنیک Code First باEntity Framework 6 درWeb API (بخش دوم)
یکشنبه 20 دی 1394در این مقاله در ادامه مقاله قبل قصد داریم نحوه رسیدگی به موجودیت های مرتبط را بررسی و برنامه ای را با استفاده از کلاس های DTO در ASP.net Web API همراه با Entity Framework ایجاد کنیم.
در این مقاله در ادامه مقاله قبل قصد داریم نحوه رسیدگی به موجودیت های مرتبط را بررسی و برنامه ای را با استفاده از کلاس های DTO در ASP.net Web API همراه با Entity Framework ایجاد کنیم.
عملی در کنترلر Employee که جزئیات کارمندان را به ما می دهد به صورت زیر می باشد :
GET :/api/employees
و نتیجه آن به صورت زیر نمایش داده می شود :
از تصویر بالا متوجه می شویم که برای Department مقدار null را دریافت کردیم. به این دلیل است که Entity Framework موجودیت های Department مرتبط را لود نکرده است.
گزارش Trace کوئری SQL زیر، این را تایید میکند :
{SELECT [Extent1].[EmployeeID] AS [EmployeeID], [Extent1].[FirstName] AS [FirstName], [Extent1].[LastName] AS [LastName], [Extent1].[DepartmentID] AS [DepartmentID] FROM [dbo].[Employees] AS [Extent1]}
دستور Select اطلاعات را از جدول Employee میگیرد و جدول Department را منبع قرار نمی دهد. اکنون Eager Loading و Lazy Loading به کار می آیند.
Eager Loading
Entity Framework موجودیت های مرتبط را به عنوان بخشی از کوئری دیتابیس اولیه بارگذاری میکند. بجای عمل GET در کنترلر Employees از کد زیر استفاده می شود :
public IQueryable<Employees> GetEmployees() { return db.Employees.Include(dept=>dept.Department); }
گزارش trace کوئری SQL به صورت زیر می باشد :
{SELECT [Extent1].[EmployeeID] AS [EmployeeID], [Extent1].[FirstName] AS [FirstName], [Extent1].[LastName] AS [LastName], [Extent1].[DepartmentID] AS [DepartmentID], [Extent2].[DepartmentID] AS [DepartmentID1], [Extent2].[DepartmentName] AS [DepartmentName] FROM [dbo].[Employees] AS [Extent1] INNER JOIN [dbo].[Departments] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]}
از گزارش بالا نتیجه میگیریم که Entity Framework یک join را در جداول Employees و department اجرا میکند.
اکنون پاسخ سرویس /api/employees به صورت زیر می باشد :
همین نتیجه را می توانیم با استفاده از Lazy Loading بدست آوریم. برای فعال کردن Lazy Loading ، ویژگی navigation مجازی را مانند کد زیر ایجاد میکنیم.
public class Employees { [Required] [Key] public int EmployeeID {get; set;} [Required] public string FirstName { get; set; } public string LastName { get; set; } public int DepartmentID { get; set;} //Foreign Key public virtual Department Department { get; set; } //Navigation Property }
و در کنترلر Employee متد Get را به صورت زیر تغییر دهید.
var Employee = db.Employees.ToList(); var dept = Employee[0].Department;
ویژگی Departmet بر روی Employee[0] سبب می شود Entity Framework به دیتابیس برای Department کوئری بزند. گزارش trace کوئری SQL به صورت زیر خواهد بود.
{ SELECT[Extent1].[EmployeeID] AS[EmployeeID], [Extent1].[FirstName] AS[FirstName], [Extent1].[LastName] AS[LastName], [Extent1].[DepartmentID] AS[DepartmentID] FROM[dbo].[Employees] AS[Extent1] } { SELECT[Extent1].[DepartmentID] AS[DepartmentID], [Extent1].[DepartmentName] AS[DepartmentName] FROM[dbo].[Department] AS[Extent1] where[Extent1].[DepartmentID] = @EntityKeyValue1 } { SELECT[Extent1].[DepartmentID] AS[DepartmentID], [Extent1].[DepartmentName] AS[DepartmentName] FROM[dbo].[Department] AS[Extent1] where[Extent1].[DepartmentID] = @EntityKeyValue1 } { SELECT[Extent1].[DepartmentID] AS[DepartmentID], [Extent1].[DepartmentName] AS[DepartmentName] FROM[dbo].[Department] AS[Extent1] where[Extent1].[DepartmentID] = @EntityKeyValue1 }
Lazy Loading در Entity Framework هر بار یک کوئری برای بازیابی موجودیت های مرتبط ارسال میکند.
منابع مدور
یک ویژگی Navigation را در کلاس Employee برای ارتباط Employee-Department تعریف کردیم. فرض کنید که میخواهیم ویژگی Navigation را برای کلاس Department تعریف کنیم ، هنگامی که مدل ها را Serialize کنیم مسئله ای ایجاد می شود. اگر داده های مرتبط را بارگذاری کنیم یک گراف مدور ایجاد می شود.
public class Department { [Required] public int DepartmentID { get; set; } [Required] public string DepartmentName { get; set; } public ICollection<Employees> Employees { get; set; } }
اکنون پاسخ سرویس /api/Employee به صورت زیر خواهد بود.
این مسئله را می توانیم با استفاده از Data Transfer Object یا DTO حل کنیم.
یک DTO عنصری است که نحوه ارسال داده بر روی شبکه را تعریف میکند. یک پوشه با نام DTO در پروژه اضافه کنید و با راست کلیک بر روی آن دو کلاس با نام های EmployeeDetailDTO و EmployeeDTO ایجاد کنید.
کدها در EmployeeDetailDTOبه صورت زیر می باشد:
public class EmployeeDetailDTO { public int EmployeeID { get; set; } public string FristName { get; set; } public string LastName { get; set; } public string DepartmentName { get; set; } public int DepartmentID { get; set; } }
و در EmployeeDTO به صورت زیر است:
public class EmployeeDTO { public int EmployeeID { get; set; } public string FristName { get; set; } public string DepartmentName { get; set; } }
اکنون عمل API را در کنترلر Employee تغییر می دهیم.
public IQueryable<EmployeeDTO> GetEmployees() { var employeedetail = from s in db.Employees select new EmployeeDTO() { EmployeeID = s.EmployeeID, FristName = s.FirstName, DepartmentName = s.Department.DepartmentName }; return employeedetail; }
پاسخ به صورت زیر خواهد بود.
عمل Get به همراه ID به صورت زیر انجام می شود :
[ResponseType(typeof(EmployeeDetailDTO))] public async Task<IHttpActionResult> GetEmployees(int id) { EmployeeDetailDTO employees = await db.Employees.Include(s => s.Department).Select( b => new EmployeeDetailDTO() { EmployeeID = b.EmployeeID, FristName = b.FirstName, LastName = b.LastName, DepartmentName = b.Department.DepartmentName, DepartmentID = b.DepartmentID }).SingleOrDefaultAsync(c => c.EmployeeID == id); if (employees == null) { return NotFound(); } return Ok(employees); }
که پاسخ برای Id=2به صورت زیر خواهد بود.
عمل Post :
این سرویس برای اضافه کردن رکوردهای Employee استفاده می شود :
[ResponseType(typeof(Employees))] public async Task<IHttpActionResult> PostEmployees(Employees employees) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Employees.Add(employees); await db.SaveChangesAsync(); db.Entry(employees).Reference(s => s.Department).Load(); var StoreEmp = new EmployeeDTO() { EmployeeID = employees.EmployeeID, FristName = employees.FirstName, DepartmentName = employees.Department.DepartmentName }; return CreatedAtRoute("DefaultApi", new { id = employees.EmployeeID }, StoreEmp); }
عمل Put :
این سرویس برای آپدیت رکوردهای Employee استفاده می شود :
[ResponseType(typeof(void))] public async Task<IHttpActionResult> PutEmployees(int id, Employees employees) { if (!ModelState.IsValid) { return BadRequest(ModelState); } if (id != employees.EmployeeID) { return BadRequest(); } db.Entry(employees).State = EntityState.Modified; try { await db.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!EmployeesExists(id)) { return NotFound(); } else { throw; } } return StatusCode(HttpStatusCode.NoContent); }
با نرم افزار Postman می توانید نتیجه این کدها را در مرورگر خود ببینید.
در مقاله بعد درباره مسیر یابی در ASP.net Web API صحبت خواهیم کرد.
- ASP.net
- 3k بازدید
- 5 تشکر