با استفاده از Repository در Asp.net می توان تغییرات را با ایجاد یک مرز بین کدهای Data Access و سایر قسمت های برنامه جدا کرد. به طور معمول در برنامه های چند لایه، BussinesLogic و DomainLogic داده ها را از منابع مختلف بازیابی می کنند، مانند: Database, Web/WCF services و…
در انواع دسترسی مستقیم، bussinesLOgic به شدت با کد دسترسی به داده ارتباط دارد که ممکن است مسائل مربوط به تعمیر و نگهداری کد به وجود بیاید؛ زیرا اگر پایگاه داده یا سرویس تغییر کند، باید کد وابسته نیز تغییر کند. بنابراین نکته اینجاست که چگونه تغییرات برای نگهداری را به حداقل برسانیم؟
- اجرای یک لایه جداسازی برای دسترسی به داده ها که می تواند به طور موثر مورد آزمایش قرار گیرد.
- اجرای کد قابل نگهداری با جدا کردن Bussines logic از منطق Access logic.
نمودار زیر یک نمای کلی از الگوی Repository را ارائه می دهد:
لایه Repository لایه Business را از لایه DataAccess جدا می کند و شامل DataMapper entity است. این entity می تواند به عنوان یک مدل موجودیت برای ارائه شیوه ای از داده ها برای انجام عملیات CRUD، با استفاده از عملیات CRUD تعریف شده در Repository استفاده شود.
Repository در ASP.NET MVC
در مورد استفاده از Repository در Asp.net MVC ، ما از لایه مدل برای تعامل با Data access و Controller ها برای انجام عملیات دسترسی به داده استفاده می کنیم. در MVC، مهم است که به الگوی Repository فکر کنید، به طوری که اگر لایه های مدل نیاز به تغییرات داشته باشند، باید حداقل یا بدون تأثیر بر روی لایه کنترلر باشد. در MVC، در نهایت کنترلر مسئول قرار دادن داده ها به view و یا دسترسی به داده ارسال شده از Http از view و ارسال آن به مدل است.
بنابراین در اینجا، اگر کنترلر وابستگی tightly coupled به مدل داشته باشد، هر تغییری در مدل بر کنترلر تاثیر می گذارد و از این رو گاهی اوقات بر روی view نیز اثر خواهد گذاشت. در این مورد، ما می توانیم از الگوی Repository همان طور که در نمودار زیر نشان داده شده است استفاده کنیم:
نمودار بالا نمودار روند Reository را توضیح می دهد. هنگامی که وب سرور درخواست را به کنترلر برای اقدامات منتقل می کند (مانند خواندن / نوشتن)، کنترلر، Repository را فراخوانی می کند و Entity model را به آن انتقال می دهد. توصیه می شود که کنترلر از تزریق وابستگی برای ایجاد Repository و روش های فراخوانی از آن استفاده کند.
Repository ،model Entity را با استفاده از Entity Framework برای انجام عملیات درخواست شده توسط کنترلر به Data Access منتقل می کند. در اینجا Repository باید از تزریق وابستگی برای اتصال dbContext به Entityframework استفاده کند. برای پیاده سازی تزریق وابستگی هر DI frameworkی (مثل Ninject Unity) می تواند استفاده شود.
Repository pattern در asp.net core
پیاده سازی Repository pattern با ASP.NET Core دارای مزایای زیر است:
سازماندهی اپلیکیشن با نداشتن وابستگی بین لایه Bussines و data access ساده تر می شود. استفاده مجدد پردازش کدهای پایگاه داده آسان تر است، زیرا کد توسط یک یا چند مخزن به طور مرکزی مدیریت می شود. business domain می تواند به صورت مستقل از یک لایه پایگاه داده مورد آزمایش قرار گیرد.
Repository interface
یک Repository interface ویژگی ها و روش های پیاده سازی را تعریف می کند. در مثال زیر، Repository interface برای داده های شخصیت فیلم ICharacterRepository است. ICharacterRepository متد ListAll و Add را برای کار با Character ها در برنامه تعریف می کند:
public interface ICharacterRepository { IEnumerable<Character> ListAll(); void Add(Character character); }
Character به صورت زیر تعریف می شود:
public class Character { public Character(string name) { Name = name; } [Key] public Guid Id { get; private set; } = Guid.NewGuid(); public string Name { get; private set; } = String.Empty; }
در این مثال، CharacterRepository محتوای پایگاه داده را مدیریت می کند و روش های ListAll و Add را اجرا می کند:
public class CharacterRepository : ICharacterRepository { private readonly ApplicationDbContext _dbContext; public CharacterRepository(ApplicationDbContext dbContext) { _dbContext = dbContext; } public IEnumerable<Character> ListAll() { return _dbContext.Characters.AsEnumerable(); } public void Add(Character character) { _dbContext.Characters.Add(character); _dbContext.SaveChanges(); } }
رجیستر یا ثبت سرویس repository
Repository و پایگاه داده در سرویس در Startup.ConfigureServices ثبت شده اند.
public void ConfigureServices(IServiceCollection services) { // Add database services. services.AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase("InMemoryDb") ); // Add framework services. services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // Register application services. services.AddScoped<ICharacterRepository, CharacterRepository>(); }
در یک کلاس که دسترسی به پایگاه داده مورد نیاز است، یک نمونه از repositoryا ز طریق Constructor درخواست می شود.
در این مثال، ICharacterRespository مورد استفاده قرار می گیرد.
public class IndexModel : PageModel { private readonly ICharacterRepository _characterRepository; public IndexModel(ICharacterRepository characterRepository) { _characterRepository = characterRepository; } public IEnumerable<Character> Characters { get; set; } public void OnGet() { PopulateCharactersIfNoneExist(); Characters = _characterRepository.ListAll(); } private void PopulateCharactersIfNoneExist() { if (!_characterRepository.ListAll().Any()) { _characterRepository.Add(new Character("Darth Maul")); _characterRepository.Add(new Character("Darth Vader")); _characterRepository.Add(new Character("Yoda")); _characterRepository.Add(new Character("Mace Windu")); } } }