برنامه نویسی

مخزن و واحد الگوی کار

بله ، من دوباره این را نمی دانم. آیا این تنها یک میلیون بار نیست که شخصی در مورد آن وبلاگ می کند؟
بله ، بله و بله اما …
همیشه خوب است که کارها را تکرار کنیم و همه ما این را می دانیم

“تکرار مادر یادگیری ، پدر عمل است که آن را به معمار موفقیت تبدیل می کند.” — Zig Ziglar

هنوز هم پیاده سازی هایی در آنجا وجود دارد که ممکن است از این امر بهره مند شود …

بنابراین بیایید با برخی از تعاریف شروع کنیم.

مخزن

به نقل از تعریف مارتین فاولر:

سیستمی با یک مدل دامنه پیچیده اغلب از یک لایه بهره می برد ، مانند نمونه ای که توسط Data Mapper (165) ارائه شده است
این اشیاء دامنه را از جزئیات کد دسترسی به پایگاه داده جدا می کند. در چنین سیستمهایی می توان ارزش ساخت یک لایه دیگر از انتزاع را داشت
بیش از لایه نقشه برداری که در آن کد ساخت و ساز پرس و جو متمرکز است. این امر زمانی مهمتر می شود که تعداد زیادی کلاس دامنه یا پرس و جو سنگین وجود داشته باشد.
در این موارد به ویژه ، اضافه کردن این لایه به به حداقل رساندن منطق پرس و جو تکراری کمک می کند. یک مخزن بین لایه های دامنه و نقشه برداری داده واسطه می شود ،
مانند یک مجموعه شیء دامنه در حافظه عمل می کند. اشیاء مشتری مشخصات پرس و جو را به صورت اعلامیه ای می سازند و آنها را برای رضایت به مخزن ارسال می کنند.
اشیاء را می توان از مخزن اضافه و حذف کرد ، همانطور که می تواند از یک مجموعه ساده از اشیاء ، و کد نقشه برداری که توسط مخزن محصور شده است
عملیات مناسب را در پشت صحنه انجام خواهد داد. از نظر مفهومی ، یک مخزن مجموعه ای از اشیاء را که در یک فروشگاه داده و عملیات ادامه دارد ، محاصره می کند
بر روی آنها انجام شد و دیدگاه شی گرا تر از لایه پایداری را ارائه می دهد. مخزن همچنین از هدف دستیابی به جدایی تمیز پشتیبانی می کند و
وابستگی یک طرفه بین دامنه و لایه های نقشه برداری داده.

خواندن منابع مختلف (MSDN الگوی مخزن ،
مارتین فاولر: مخزن و غیره) درباره الگوی مخزن که خواص زیر ظهور می کند:

  • این نقشه بین اشیاء دامنه و اشیاء داده نقشه برداری می کند
  • این لایه داده را در معرض جهان خارج قرار نمی دهد
  • این همه الگوهای دسترسی به داده ها را در یک مکان ادغام می کند ، بنابراین به کدگذاری کد کمک می کند
  • این یک مسئولیت واحد دارد
  • اجرای آن ساده است
  • این یک وابستگی یک طرفه بین دامنه و لایه داده است

یک مثال ساده مخزن برنامه زیر (C#) است:

public interface IApplicationRepository
{
    Task DeleteAsync(int id);
    Task<ApplicationModel> GetAsync(int id);
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با ارائه رابط می توانیم اجرای را در بالای توسعه دهنده قرار دهیم تا کتابخانه دسترسی به داده های مورد نظر خود را انتخاب کنیم.
آرگومان و مقادیر بازگشت این رابط باید اشیاء خاص دامنه باشد و نه اشیاء داده برای جلوگیری از ریختن داده ها
به لایه های دیگر و جدایی تمیز داشته باشید.

با استفاده از موارد فوق این فرصت را داشتم که اجرای اصلی را با هر چیزی که می خواستم با آن آزمایش کنم تغییر دهم.
ابتدا همه چیز EF بود ، سپس Simple.data و سپس Dapper و غیره
در پایان از SQLConnection استفاده می شود. تغییر اجرای اساسی بسیار آسان است.

شما ممکن است فکر کنید که تغییر اجرای آن اتفاق نمی افتد (از EF به Dapper یا از nibernate به EF یا Dapper و غیره مهاجرت کنید)
اما می تواند اتفاق بیفتد و یک انتزاع واقعا ارزان در مورد اجرای لایه داده شما است. این امر باعث جداسازی تمیز می شود که همیشه کاری است که ارزش انجام آن را دارد.
این اجازه می دهد تا برنامه به طور مستقیم به کتابخانه دسترسی به داده ها وابسته نباشد و امکان تغییر آینده را با هزینه اندک فراهم می کند.
به عنوان مثال اگر شما برنامه ای دارید که از nibernate استفاده می کند ، که ممکن است در گذشته انتخاب خوبی باشد ، برخی موارد را از دست نمی دهید
این ORM دیگر مانند تماس های Async یا حتی هسته جدید .NET که ممکن است برای nibernate اتفاق بیفتد ، ارائه می دهد. Dapper و EF قبلاً موارد فوق را دارند.

اجرای رابط برای کار با لایه داده به چیزی نیاز دارد. این می تواند یک SQLConnection ، DBContext (EF) ، جلسه (nibernate) و غیره باشد.
این به هر مخزن تزریق می شود و به طور کلی در واحد کار اجرا می شود.

واحد کار

به نقل از تعریف مارتین فاولر:

یک واحد کار همه کارهایی را که در طی یک معامله تجاری انجام می دهید ، پیگیری می کند که می تواند بر پایگاه داده تأثیر بگذارد.
هنگامی که تمام شد ، هر آنچه را که باید انجام شود برای تغییر پایگاه داده در نتیجه کار شما مشخص می کند.

بنابراین UOW (واحد کار) وظیفه نگه داشتن شیء DB (SQLConnection ، DBContext) و رسیدگی به تعهد نهایی را دارد تا همه چیز را به DB ادامه دهد.

یک رابط کاربری ساده (C#) که باید اجرا شود موارد زیر است:

public interface IUnitOfWork : IDisposable
{
    IApplicationRepository Applications { get; }
    Task CommitAsync();
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این فقط یک بسته بندی در اطراف شیء DB ما (SQLConnection ، DBContext و غیره) و اجرای تعهد است.
هنگامی که ما یک UOW داریم ، همه مخازن لازم را در دست داریم ، بنابراین تعامل با آنها بسیار آسان است.

EF اجرای و استفاده از آن

اکنون ما اجرای زیر را برای مخزن برنامه داریم

public class ApplicationRepository : IDataAccess<ApplicationDbModel>, 
                                        IApplicationRepository
{
    public ApplicationRepository(DbContext dbContext, IMapper mapper) : 
        base(dbContext, mapper)
    {
    }

    public Task DeleteAsync(int id) => base.DeleteAsync(id);

    public async Task<ApplicationModel> GetAsync(int id)
    {
            var application = await GetAll()
                        .Where(p => p.Id == id)
                        .SingleOrDefaultAsync();
            return mapper<ApplicationModel>(application);
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در جایی که مخزن پایه اجرای EF از رابط زیر است:

public interface IDataAccess<T> where T : class
{
    IQueryable<T> GetAll();
    Task<T> GetByIdAsync(params object[] keyValues);
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    Task DeleteAsync(params object[] keyValues);
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اجرای یک کتابخانه دسترسی به داده های دیگر بسیار آسان است. اجرای dapper از مخزن برنامه
به عنوان پارامتر سازنده ، SQLConnection و اجرای واقعی روش های رابط. این است

واحد اجرای کار به شرح زیر است:

public sealed class UnitOfWork : IUnitOfWork
{
    private readonly IMapper _mapper;
    private DbContext _dbContext;

    public UnitOfWork(DbContext dbContext, IMapper mapper)
    {
        _dbContext= dbContext;
        _mapper = mapper;
    }

    public Task<int> CommitAsync()
    {
        return _dbContext.SaveChangesAsync();
    }

    public IApplicationRepository Applications => 
        new ApplicationRepository(_dbContext, _mapper);

    //Implement IDisposable
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این یک اجرای ساده از UOW است. مهم نیست که برخی از ویژگی ها مانند دست زدن به معامله وجود ندارد
(dbcontext.database.begintransaction () و سپس تعهد یا بازپرداخت) یک کارخانه مخزن و غیره که اجرای آن نسبتاً آسان است.

و چگونه از این استفاده می شود؟

بیایید فرض کنیم که یک واحد کارخانه کار اجرا شده است تا کد این باشد:

using (var uow = _unitOfWorkFactory.Create())
{
    var application = await uow.Applications.GetAsync(1, 1);
    await uow.Applications.DeleteAsync(application.Id);
    await uow.CommitAsync();
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

آسان و تمیز ، اینطور نیست؟ همه چیز در یک مکان است ، در پایان آن متعهد و به درستی دفع می شود.
از آنجا که EF اتصال را از طریق DBContext در معرض دید قرار می دهد ، ما در واقع می توانیم از Dapper نیز استفاده کنیم و یک مخزن دسترسی به داده های مختلط داشته باشیم
به منظور رسیدگی به برخی از نقاط مهم در جایی که EF خوب بازی نمی کند.

پایان

مخزن و واحد الگوهای کاری بسیار آسان است. آنها یک انتزاع دسترسی به داده های مناسب را ارائه می دهند و فقط شیء دامنه مورد نیاز را در معرض نمایش می گذارند
و شیء داده را در لایه های بالایی ریخته نکنید. تنها چیزی که برای استفاده از این مورد لازم است تزریق واحد کارخانه کار است و ما DB خود را در دست داریم.
امیدوارم این مفید باشد. هر نظر ، بحث یا رفع بسیار استقبال می شود.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا