نمایش نتایج 1 تا 8 از 8

نام تاپیک: طراحی یک ریپازیتوری عمومی

  1. #1

    طراحی یک ریپازیتوری عمومی

    سلام

    دوستان من میخواهم در mvc core2 یک ریپازیتوری عمومی داشته باشم که عملیات CURD رو نخواهم هر بار در ریپازیتوری هر موجودیتی انجام بدم . کدها بصورت زیر هست

    کد اینترفیس :

    public interface IRepository<TEntity>
    where TEntity : class
    {
    IQueryable<TEntity> GetAll();
    Task Create(TEntity entity);
    Task Update(int id, TEntity entity);
    Task Delete(int id);
    }



    کدهای مربوط به ریپازیتوری عمومی :


    public class RepositoryBase<TEntity> : IRepository<TEntity>


    {
    private readonly DataContext _dbContext;
    public RepositoryBase(DataContext dbContext)
    {
    _dbContext = dbContext;
    }
    public IQueryable<TEntity> GetAll()
    {
    return _dbContext.Set<TEntity>().AsNoTracking();
    }

    public async Task Create(TEntity entity)
    {
    await _dbContext.Set<TEntity>().AddAsync(entity);
    await _dbContext.SaveChangesAsync();
    }
    public async Task Update(int id, TEntity entity)
    {
    _dbContext.Set<TEntity>().Update(entity);
    await _dbContext.SaveChangesAsync();
    }
    public async Task Delete(int id)
    {
    var entity = await _dbContext.Set<TEntity>().FindAsync(id);
    _dbContext.Set<TEntity>().Remove(entity);
    await _dbContext.SaveChangesAsync();
    }


    }



    حالا هر ریپازیتوری رو که بخام داشته باشم از RepositoryBase مشتق می کنم و مشکل همینجاست من میخام در ریپازیتوری های مشتق شده اولا از دیتاکانتکس استفاده نکنم و دیتاکانتکس فقط در RepositoryBase فراخونی شده باشه و دوما در کنترلرها این ریپازیتوری رو بدون new کردن داشته باشم و از DI استفاده کنم . منتها اگر بخواهم از تزریق وابستگی هم استفاده کنم باید برای هر ریپازیتوری یک اینترفیس تعریف کنم و در استارت آپ سرویس اون رو فعال کنم . ( اگر هم بخام این دو حالت اتفاق نیفته مدام باید دیتاکانتکس رو در کنترلر فراخوانی کنم و از new کردن استفاده کنم )


    public class GroupRepository :RepositoryBase<Group>
    {
    public GroupRepository(DataContext dbContext) : base(dbContext)
    {
    }
    }




    ممنون میشم راهنمایی بفرمایید

  2. #2

    نقل قول: طراحی یک ریپازیتوری عمومی

    اول اینکه هر چند استفاده از یک Repository مادر اشکالی نداره ولی بهترین روش پیاده سازی الگوی Repository نیست. وقتی شما برای همه ی مدل ها از Repository مادر استفاده می کنید یعنی دارید به خودتون و سایر اعضای تیم برنامه نویسی اعلام می کنید که انجام هر چهار عمل اصلی روی اون جدول مجازه. در حالی که در عمل اینطور نیست.

    مثلا هیچوقت رکوردی از جدول سفارشهای یک فروشگاه پاک نمیشه. ولی از اونجایی که در ریپوزیتوری مادر شما عملیات Delete دارید امکان حذف کردن سفارش رو فراهم کردید. وقتی تنها کار میکنید یا در یک تیم کوچک هستید این مسئله به چشم نمیاد ولی در پروژه های بزرگتر با تیم بزرگتر کنترل کردن کدهای تیم مشکله و ممکنه یکی از برنامه نویسان برای انجام یک تسک از متدهایی استفاده کنه که عملا مجاز نیست.

    ممکنه بگید من وقت و حوصله ی نشتن ریپوزیتوری جدا برای تک تک مدلها ندارم و می خوام از ریپوزیتوری مادر استفاده کنم. اشکالی نداره ولی باید حواستون به اثرات جانبیش باشه.

    چیزی که در GroupRepository پیاده کردید درسته و فقط باید وابستگی رو در Startup تزریق کنید. دقت کنید که اگر روی این ریپوزیتوری یک لایه ی سرویس وجود داره فقط کافیه همون رو ترزیق کنید. DI میاد و ریپوزیتوری و DataContext رو خودش ایجاد (تزریق میکنه)

    نیاز به Interface ندارید می توانید یک کلاس رو بدون اینترفیس هم تزریق کنید. هرچند استفاده ا Interface بهتره. ولی در اینکه باید تک تک ریپوزیتوری ها در DI تعریف کنید هیچ شکی نیست.

    معمولا روی Repository باید از UnitOfWork استفاده کنید. کنترلرها هم از Repository استفاده نمیکنن. از لایه ی Service استفاده میکنن. پس درستش اینه که روی ریپوزیتوری یک لایه ی Service داشته باشید.

    همچنین در یک Repository نباید از IQueryable استفاده کنید. خروجی گزارشهای یک ریپوزیتوری فقط باید به صورت List باشه.

  3. #3

    نقل قول: طراحی یک ریپازیتوری عمومی

    بسیار ممنون و سپاسگزار


    بهترین روش پیاده سازی رو میشه بفرمایید چه روشی هست؟


    ممنون . ولی تعداد جداولی که هر 4 عمل رو نیاز نداشته باشن زیاد نیست درسته ؟ میتونیم اونا رو جدا داشته باشیم و از ریپازیتوری مادر ارث بری نداشته باشن؟

  4. #4

    نقل قول: طراحی یک ریپازیتوری عمومی

    من ریپازیتوری رو بصورت زیر در startup.cs اضافه کردم :

          services.AddScoped<GroupRepository>();


    ولی برای یه پروژه معمولی هم که درنظر بگیریم تعداد ریپازیتوری ها زیاد هست . یعنی باید این خط کد رو مثلا 50 بار در استارت آپ با با ریپازیتوریهای مختلف فراخوانی کنیم . راهی نیست که یکبار این کد نوشته بشه ؟

    IQueryable هم به این دلیل استفاده کردم که بتونم بصورت کلی از روی متد GetAll کوِيری بزنم مثلا اینطوری :

    (from rows in _repository.GetAll()
    select new GroupViewModel
    {
    Id = rows.Id,
    Name = rows.Name,
    ParentId = rows.ParentId
    }).ToList();





    یعنی نوشتن به این صورت اشتباهه ؟

  5. #5

    نقل قول: طراحی یک ریپازیتوری عمومی

    1- باید از AddTransient استفاده کنید.
    2- هدف استفاده از Repository دریافت اطلاعات از دیتابیس و ذخیره اونها به صورت موقت در حافظه هست. وقتی از IQueryable استفاده می کنید این اتفاق نمیوفته . کلاس IQueryable فقط کوئری رو در خودش نگه میداره و نه خود اطلاعات رو. اطلاعات یک Qoueryable فقط در زمان اجرا وقتی به اون خط میرسه میره و از دیتابیس دریافت میشه. این کاملا بر خلاف هدف استفاده از Repository هست. برای نمونه ای که اشاره کردید باید یک متد جدا تعریف کنید.
    3-اگر می خواهید به همه چیز در همه ی زمان ها دسترسی داشته باشید از Repository استفاده نکنید.

    اول Repostory مثل یک ریل قطار میمونه. نمیزاره به هر مسیری برید ولی سرعت رسیدن شمارو به مقصدهای مشخص بیشتر میکنه.
    دوم اینکه Repository اطلاعات موجود در دیتابیس رو که در دیسک ذخیره شده خارج میکنه و در رم نگه میداره. اگر بخواهید چند عملیات روی دیتابیس انجام بدید لازم نیست هربار به دیتابیس مراجعه کنید. تغییرات در Repository انجام میشه و هر وقت کار شما با Repository تمام شد دستور ذخیره سازی رو میدهید.
    به همین دلیل در یک Repository نباید دستور ذخیره سازی و IQueryable داشته باشید. ذخیره سازی باید در UnitOfWork انجام بشه. اطلاعات هم باید در List باشه که از کوئری خارج بشه. وگرنه هیچ معنی نداره که شما روی Entityframework بیایید یک لایه جدید اضافه کنید. EF همون Repository نیست.

  6. #6
    کاربر دائمی آواتار alireza_s_84
    تاریخ عضویت
    فروردین 1386
    محل زندگی
    اهواز
    پست
    1,191

    نقل قول: طراحی یک ریپازیتوری عمومی

    مثلا هیچوقت رکوردی از جدول سفارشهای یک فروشگاه پاک نمیشه. ولی از اونجایی که در ریپوزیتوری مادر شما عملیات Delete دارید امکان حذف کردن سفارش رو فراهم کردید. وقتی تنها کار میکنید یا در یک تیم کوچک هستید این مسئله به چشم نمیاد ولی در پروژه های بزرگتر با تیم بزرگتر کنترل کردن کدهای تیم مشکله و ممکنه یکی از برنامه نویسان برای انجام یک تسک از متدهایی استفاده کنه که عملا مجاز نیست.
    هرچند مدیر کل سیستم این اجازه رو داره که تاریخچه هر رکوردی رو حذف کنه!
    مثال ارائه شده برای پروژه های بزرگ و کوچک اصلا مثال خوبی نیست چون اگر قرار باشه یکی از اعضای تیم خرابکاری کنه این خرابکاری میتونه از طریق کدنویسی مستقیم انجام بشه یعنی بدون Repository! اگر یکی از برنامه نویسان از متدهای غیرمجاز استفاده کنه میتونه شامل همه الگوهای طراحی بشه پس همه رو میذاریم کنار!

    public interface IRepository<TEntity> where TEntity : class
    {
    IQueryable<TEntity> GetAll();
    Task Create(TEntity entity);
    Task Update(int id, TEntity entity);
    Task Delete(int id);
    }
    به جای اینکه برای هر مدل یک Repository بنویسید همین اینترفیس رو فقط در یک کلاس پیاده سازی کنید و بصورت Scoped تزریق کنید.
    services.TryAddScoped(typeof(IRepository<>), typeof(Repository<>));

    اینطوری نیازی به تعریف Repository برای هر کلاس مدل ندارید!
    اینترفیس IRepository باید در پکیجی جدا از کلاس تعریف بشه Repository بعد به ازای هر نوع اتصال پایگاه داده (مثلا برای EF) یک پکیج جدا و برای MongoDb یک پکیج جدا نوشته میشه و پیاده سازی صورت میگیره.
    یکی از اهداف Repository آینده نگری برای تعویض نحوه ارتباط با پایگاه داده است.
    به این نکته هم خیلی توجه کنید:
    هدف استفاده از Repository دریافت اطلاعات از دیتابیس و ذخیره اونها به صورت موقت در حافظه هست. وقتی از IQueryable استفاده می کنید این اتفاق نمیوفته . کلاس IQueryable فقط کوئری رو در خودش نگه میداره و نه خود اطلاعات رو. اطلاعات یک Qoueryable فقط در زمان اجرا وقتی به اون خط میرسه میره و از دیتابیس دریافت میشه. این کاملا بر خلاف هدف استفاده از Repository هست. برای نمونه ای که اشاره کردید باید یک متد جدا تعریف کنید.
    همچنین برای پشتیبانی از سناریوهایی که نیازمند کوئری نویسی مستقیم هستن میتونید به اینترفیس IRepository یک پراپرتی از نوع IQueryable<TEntity> قرار بدین که اجازه کوئری نویسی مستقیم رو به شما میده.
    متد SaveChanges رو هم میتونید (بدون نگاه سختگیرانه با توجه به گفته های دوستمون) اضافه کنید.
    نکته اخر همیشه نمیشه همه چیز رو باهم و ایده آل داشت پس زیاد سخت نگیرید خیلی از قوانین فقط دست و پاگیر هستند اما نه همه اونها!

  7. #7

    نقل قول: طراحی یک ریپازیتوری عمومی

    مرسی استاد

    من یک ریپازیتوری عمومی نوشتم که هر بار نخام کدهای تکراری رو در هر ریپازیتوری بنویسم اما برای هر مدلی یک سری متدهای خاص هم هست .برای اونا که مجبور میشم ریپازیتوری تعریف کنم و بعد باید سرویسشون رو فعال کنم .

    من کدها رو یه سری تغییر دادم بصورت زیر :
    در واقع یک اینترفیس دارم بصورت زیر :

    public interface IRepository<TEntity>
    where TEntity : class
    {
    IEnumerable<TEntity> GetAll();
    TEntity GetById(int id);
    void Add(TEntity entity);
    void Update(int id, TEntity entity);
    void Delete(int id);
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);

    }



    یک ریپازیتوری عمومی :


    public abstract class RepositoryBase<TEntity> : IRepository<TEntity>
    where TEntity : class
    {
    private readonly DataContext _dbContext;
    public RepositoryBase(DataContext dbContext)
    {
    _dbContext = dbContext;
    }
    public IEnumerable<TEntity> GetAll()
    {
    return _dbContext.Set<TEntity>().ToList();
    // return _dbContext.Set<TEntity>().AsNoTracking();
    }
    public TEntity GetById(int id)
    {
    return _dbContext.Set<TEntity>().Find(id);
    }
    public void Add(TEntity entity)
    {
    _dbContext.Set<TEntity>().Add(entity);
    }

    public void Update(int id,TEntity entity)
    {
    _dbContext.Entry(entity).State = EntityState.Modified;
    }

    public void Delete(int id)
    {
    TEntity entity = _dbContext.Set<TEntity>().Find(id);
    if (entity != null) _dbContext.Set<TEntity>().Remove(entity);
    }
    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
    return _dbContext.Set<TEntity>().Where(predicate).ToList( );
    }
    }



    برای متد savechange هم بصورت زیر :


    public interface IUnitOfWork : IDisposable
    {
    int Save();
    }


    و


    public class UnitOfWork : IUnitOfWork
    {
    private readonly DataContext _dbContext;
    public UnitOfWork(DataContext dbContext)
    {
    _dbContext = dbContext;
    }
    public int Save()
    {
    return _dbContext.SaveChanges();
    }
    #region IDisposable Support
    private bool disposedValue;
    protected virtual void Dispose(bool disposing)
    {
    if (!disposedValue)
    {
    if (disposing)
    {
    _dbContext.Dispose();
    }
    disposedValue = true;
    }
    }
    void IDisposable.Dispose()
    {
    Dispose(true);
    }
    }




    حالا هر مدلی رو که بخام متد اضافه تری هم داشته باشن از RepositoryBase ارث میبرن . و مجبور میشم مدام در استارت آپ سرویسشون رو فعال کنم . و اگر درست متوجه شده باشم شما میگین که برای اون متدهای خاص یه IQueryable داشته باشم در ریپازیتوری بیس ؟که نخام برای هر مدل ریپازیتوری بنویسم و سرویس هم نمیخاد فعال شه.


    public virtual IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
    {
    IQueryable<TEntity> query = _dbContext.Set<TEntity>(); ;
    if (filter != null)
    query = query.Where(filter);
    if (orderBy != null)
    query = orderBy(query);
    return query;
    }


  8. #8
    کاربر دائمی آواتار alireza_s_84
    تاریخ عضویت
    فروردین 1386
    محل زندگی
    اهواز
    پست
    1,191

    نقل قول: طراحی یک ریپازیتوری عمومی

    این لینک رو مطالعه کنید:
    Generic Repository


تاپیک های مشابه

  1. آموزش: کارگاه رایگان آموزش طراحی یک بازی آنلاین در دانشگاه آزاد تهران جنوب (عمومی)
    نوشته شده توسط علی متقی پور در بخش برنامه نویسی مبتنی بر Microsoft .Net Framework
    پاسخ: 0
    آخرین پست: دوشنبه 26 بهمن 1394, 08:26 صبح
  2. کارگاه رایگان آموزش طراحی یک بازی آنلاین در دانشگاه آزاد تهران جنوب (عمومی)
    نوشته شده توسط علی متقی پور در بخش توسعه وب (Web Development)
    پاسخ: 0
    آخرین پست: دوشنبه 26 بهمن 1394, 08:23 صبح
  3. طراحی یک سند حسابداری که دارای ستونهای بد/بس/مانده ؟
    نوشته شده توسط vbstar در بخش گزارش سازی با Crystal Report
    پاسخ: 7
    آخرین پست: چهارشنبه 15 مهر 1383, 11:49 صبح
  4. طراحی یک جدول مناسب
    نوشته شده توسط delphiman00 در بخش برنامه نویسی در Delphi
    پاسخ: 6
    آخرین پست: چهارشنبه 06 خرداد 1383, 18:49 عصر
  5. طراحی یک نوع grid خاص
    نوشته شده توسط ladan_t در بخش VB.NET
    پاسخ: 1
    آخرین پست: سه شنبه 26 اسفند 1382, 00:07 صبح

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •