জেনেরিক সংগ্রহশালা বনাম প্রতিটি বস্তুর জন্য নির্দিষ্ট সংগ্রহস্থল তৈরির সুবিধা?


132

আমরা একটি এএসপি.এনইটি এমভিসি অ্যাপ্লিকেশন বিকাশ করছি এবং এখন সংগ্রহস্থল / পরিষেবা ক্লাস তৈরি করছি। আমি ভাবছি যে জেনেরিক IRepository ইন্টারফেস তৈরি করার যে কোনও বড় সুবিধা রয়েছে যা সমস্ত সংগ্রহস্থলগুলি প্রয়োগ করে, বনাম, প্রতিটি সংগ্রহস্থলের নিজস্ব অনন্য ইন্টারফেস এবং পদ্ধতিগুলির সেট রয়েছে।

উদাহরণস্বরূপ: একটি জেনেরিক IRepository ইন্টারফেস দেখতে পারে ( এই উত্তর থেকে নেওয়া ):

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

প্রতিটি সংগ্রহস্থল এই ইন্টারফেসটি প্রয়োগ করবে, উদাহরণস্বরূপ:

  • CustomerRepository: IRepository
  • ProductRepository: IRepository
  • প্রভৃতি

পূর্ববর্তী প্রকল্পগুলিতে আমরা যে বিকল্পটি অনুসরণ করেছি তা হ'ল:

public interface IInvoiceRepository : IDisposable
{
    EntityCollection<InvoiceEntity> GetAllInvoices(int accountId);
    EntityCollection<InvoiceEntity> GetAllInvoices(DateTime theDate);
    InvoiceEntity GetSingleInvoice(int id, bool doFetchRelated);
    InvoiceEntity GetSingleInvoice(DateTime invoiceDate, int accountId); //unique
    InvoiceEntity CreateInvoice();
    InvoiceLineEntity CreateInvoiceLine();
    void SaveChanges(InvoiceEntity); //handles inserts or updates
    void DeleteInvoice(InvoiceEntity);
    void DeleteInvoiceLine(InvoiceLineEntity);
}

দ্বিতীয় ক্ষেত্রে, এক্সপ্রেশনগুলি (লিনকিউ বা অন্যথায়) সম্পূর্ণরূপে সংগ্রহস্থল প্রয়োগে অন্তর্ভুক্ত থাকবে, যে কেউ পরিষেবাটি প্রয়োগ করছে কেবল কোন রেপোজিটরি ফাংশন কল করতে হবে তা জানতে হবে।

আমার ধারণা সার্ভিস ক্লাসে সমস্ত এক্সপ্রেশন সিনট্যাক্স লেখার এবং সংগ্রহশালায় যাওয়ার সুবিধা আমি দেখছি না। এর অর্থ এই নয় যে সহজেই মেসআপআপ লিনকুই কোডটি বহু ক্ষেত্রে নকল করা হচ্ছে?

উদাহরণস্বরূপ, আমাদের পুরানো চালান পদ্ধতিতে, আমরা কল করি

InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)

কয়েকটি ভিন্ন পরিষেবা (গ্রাহক, চালান, অ্যাকাউন্ট, ইত্যাদি) থেকে এটি একাধিক জায়গায় নিম্নলিখিত লেখার চেয়ে অনেক পরিচ্ছন্ন বলে মনে হচ্ছে:

rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);

সুনির্দিষ্ট পদ্ধতির ব্যবহারের জন্য আমি দেখতে পাচ্ছি একমাত্র অসুবিধা হ'ল আমরা get * ফাংশনগুলির অনেক অনুমতি দিয়ে শেষ করতে পারি, তবে এটি এখনও সার্ভিস ক্লাসগুলিতে অভিব্যক্তি যুক্তিটিকে ধাক্কা দেওয়া ভাল বলে মনে হয়।

আমি কী মিস করছি?


পূর্ণ ওআরএম সহ জেনেরিক সংগ্রহস্থলগুলি অকেজো মনে হচ্ছে less আমি এখানে বিশদ আলোচনা করেছি ।
অমিত জোশী

উত্তর:


169

এটি রিপোজিটরি প্যাটার্নের মতোই পুরানো একটি সমস্যা। লিনকিউ'র সাম্প্রতিক প্রবর্তন IQueryable, একটি কোয়ের একরকম উপস্থাপনা, এই বিষয়টি নিয়ে অনেক আলোচনার কারণ করেছে।

জেনেরিক সংগ্রহশালা কাঠামো তৈরি করতে খুব পরিশ্রম করার পরে আমি নিজেই নির্দিষ্ট সংগ্রহস্থলগুলিকে পছন্দ করি। আমি যে চতুর প্রক্রিয়াটি চেষ্টা করেছি তা বিবেচনা না করেই আমি সর্বদা একই সমস্যাটি শেষ করেছিলাম: একটি সংগ্রহস্থলটি ডোমেনের মডেল হওয়ার একটি অংশ, এবং সেই ডোমেনটি জেনেরিক হয় না। প্রতিটি সত্তা মুছে ফেলা যায় না, প্রতিটি সত্তা যুক্ত করা যায় না, প্রতিটি সত্তার কোনও ভাণ্ডার নেই। প্রশ্নগুলি বন্যভাবে পরিবর্তিত হয়; সংগ্রহস্থল API সত্তার মতোই অনন্য হয়ে ওঠে।

একটি প্যাটার্ন যা আমি প্রায়শই ব্যবহার করি তা হ'ল নির্দিষ্ট সংগ্রহস্থল ইন্টারফেস থাকে, তবে বাস্তবায়নের জন্য একটি বেস ক্লাস। উদাহরণস্বরূপ, লিনকিউ থেকে এসকিউএল ব্যবহার করে আপনি এটি করতে পারেন:

public abstract class Repository<TEntity>
{
    private DataContext _dataContext;

    protected Repository(DataContext dataContext)
    {
        _dataContext = dataContext;
    }

    protected IQueryable<TEntity> Query
    {
        get { return _dataContext.GetTable<TEntity>(); }
    }

    protected void InsertOnCommit(TEntity entity)
    {
        _dataContext.GetTable<TEntity>().InsertOnCommit(entity);
    }

    protected void DeleteOnCommit(TEntity entity)
    {
        _dataContext.GetTable<TEntity>().DeleteOnCommit(entity);
    }
}

DataContextআপনার পছন্দের কাজের ইউনিট দিয়ে প্রতিস্থাপন করুন । একটি উদাহরণ বাস্তবায়ন হতে পারে:

public interface IUserRepository
{
    User GetById(int id);

    IQueryable<User> GetLockedOutUsers();

    void Insert(User user);
}

public class UserRepository : Repository<User>, IUserRepository
{
    public UserRepository(DataContext dataContext) : base(dataContext)
    {}

    public User GetById(int id)
    {
        return Query.Where(user => user.Id == id).SingleOrDefault();
    }

    public IQueryable<User> GetLockedOutUsers()
    {
        return Query.Where(user => user.IsLockedOut);
    }

    public void Insert(User user)
    {
        InsertOnCommit(user);
    }
}

লক্ষ্য করুন সংগ্রহস্থলের সার্বজনীন এপিআই ব্যবহারকারীদের মোছার অনুমতি দেয় না। এছাড়াও, এক্সপোজারিং IQueryableহ'ল পোকার সম্পূর্ণ ক্যান - এই বিষয়টিতে পেটের বোতামগুলির মত অনেকগুলি মতামত রয়েছে।


9
সিরিয়াসলি, দুর্দান্ত উত্তর। ধন্যবাদ!
বীপ বীপ

5
সুতরাং আপনি কীভাবে এটি দিয়ে আইওসি / ডিআই ব্যবহার করবেন? (আমি আইওসি-তে একজন শিক্ষানবিশ) আপনার প্যাটার্নের সাথে আমার সম্পূর্ণ প্রশ্ন: stackoverflow.com/questions/4312388/…
এবং

36
"একটি সংগ্রহস্থলটি ডোমেনের মডেলিংয়ের একটি অংশ, এবং সেই ডোমেনটি জেনেরিক হয় না every প্রতিটি সত্তা মোছা যায় না, প্রতিটি সত্তাও যুক্ত করা যায় না, প্রতিটি সত্তার কোনও ভাণ্ডার নেই" নির্ভুল!
adamwtiko

আমি জানি এটি একটি পুরানো উত্তর, তবে আমি উত্সাহী আমি যদি ইচ্ছাকৃতভাবে সংগ্রহস্থল শ্রেণি থেকে কোনও আপডেট পদ্ধতি ছেড়ে চলে যাই। এটি করার একটি পরিষ্কার উপায় খুঁজে পেতে আমার সমস্যা হচ্ছে।
rtf

1
ওল্ডি কিন্তু গুডি। এই পোস্টটি অবিশ্বাস্যভাবে বুদ্ধিমান এবং পড়া উচিত এবং পুনরায় পড়তে হবে তবে সমস্ত ভাল-বিকাশকারী বিকাশকারী। ধন্যবাদ ব্রায়ান ওয়াটস আমার বাস্তবায়ন সাধারণত ড্পার ভিত্তিক, কিন্তু পূর্বনির্মাণটি একই। বৈশিষ্ট্যগুলিতে অপ্ট-ইন করে এমন ডোমেনকে উপস্থাপন করার জন্য নির্দিষ্ট সংগ্রহস্থলগুলির সাথে বেস সংগ্রহস্থল ory
পিমব্রউবাররা

27

ব্রায়ানের পোস্টের সাথে আমি আসলে কিছুটা দ্বিমত পোষণ করি। আমি মনে করি তিনি ঠিক বলেছেন, শেষ পর্যন্ত সবকিছুই খুব স্বতন্ত্র এবং আরও অনেক কিছু। তবে একই সাথে, বেশিরভাগটি আপনার নকশার সাথে সাথে প্রকাশিত হয় এবং আমি দেখতে পাই যে জেনেরিক সংগ্রহশালা তৈরি করা এবং এটি আমার মডেল বিকাশের সময় ব্যবহার করে, আমি খুব দ্রুত একটি অ্যাপ্লিকেশন পেতে পারি, তারপরে আমি আরও সুনির্দিষ্টতার সাথে রিফ্যাক্টর পাই এটি করা প্রয়োজন।

সুতরাং, এর মতো ক্ষেত্রে, আমি প্রায়শই একটি জেনেরিক আইরিপোসিটরি তৈরি করেছি যাতে সম্পূর্ণ সিআরইউডি স্ট্যাক থাকে এবং এটি আমাকে এপিআই দিয়ে খেলতে এবং লোকজনকে ডাব্লু / ইউআই খেলতে দেয় এবং সমান্তরালে ইন্টিগ্রেশন এবং ব্যবহারকারীর স্বীকৃতি পরীক্ষা করতে দেয়। তারপরে, আমি যেমন খুঁজে পেয়েছি রেপো ইত্যাদিতে আমার নির্দিষ্ট প্রশ্নগুলি প্রয়োজন, আমি সেই নির্ভরতা ডাব্লু / নির্দিষ্টটি প্রতিস্থাপনের প্রয়োজন এবং প্রয়োজনে সেখান থেকে শুরু করতে শুরু করি। অন্তর্নিহিত ইমপ্ল। তৈরি করা এবং ব্যবহার করা সহজ (এবং সম্ভবত একটি মেমোরি ডিবি বা স্ট্যাটিক অবজেক্টস বা উপহাসযুক্ত বস্তুগুলি বা যাই হোক না কেন) ook

এটি বলেছিল, আমি ইদানীং যা করতে শুরু করেছি তা হচ্ছে আচরণটি ভেঙে দেওয়া। সুতরাং, আপনি যদি আইডাটাফ্যাচার, আইডিটাউপডেটার, আইডাটাআইনেসার এবং আইডাটাডেলেটারের জন্য ইন্টারফেস করেন (উদাহরণস্বরূপ) আপনি ইন্টারফেসের মাধ্যমে আপনার প্রয়োজনীয়তাগুলি সংজ্ঞায়িত করতে মিশ্র-এবং ম্যাচ করতে পারেন এবং তারপরে কিছু বা সমস্তটির যত্ন নেওয়া বাস্তবায়ন রয়েছে এবং আমি তা করতে পারি আমি অ্যাপটি তৈরি করার সময় এখনও সমস্ত প্রয়োগটি ব্যবহারের জন্য ইনজেক্ট করুন।

পল


4
জবাব @ পল এর জন্য ধন্যবাদ। আমি আসলে সেই পদ্ধতির চেষ্টাও করেছি। আমি প্রথমে চেষ্টা করেছিলাম কীভাবে উদারভাবে প্রকাশ করতে পারি GetById(),। আমি ব্যবহার করা উচিত IRepository<T, TId>, GetById(object id)অথবা অনুমানের এবং ব্যবহার করতে GetById(int id)? সম্মিলিত কী কীভাবে কাজ করবে? আমি অবাক হয়েছি যে আইডি দ্বারা জেনেরিক নির্বাচনটি কোনও উপযুক্ত বিমূর্ততা ছিল। যদি তা না হয় তবে আর কী কী জেনারিক স্টোরগুলি এককভাবে প্রকাশ করতে বাধ্য হবে? ইন্টারফেস নয়, বাস্তবায়ন বিমূর্ত করার পিছনে যুক্তিটির এই রেখাটি ছিল ।
ব্রায়ান ওয়াটস

10
এছাড়াও, একটি জেনেরিক ক্যোয়ারী মেকানিজম হ'ল একটি ওআরএমের দায়িত্ব। আপনার সংগ্রহস্থলগুলি জেনেরিক ক্যোয়ারী প্রক্রিয়াটি ব্যবহার করে আপনার প্রকল্পের সত্তাগুলির জন্য নির্দিষ্ট প্রশ্নের প্রয়োগ করা উচিত implementing আপনার রিপোজিটরির গ্রাহকরা যদি নিজের সমস্যার ডোমেন, যেমন রিপোর্টিংয়ের অংশ না হয় তবে তাদের নিজের প্রশ্ন লিখতে বাধ্য করা উচিত নয়।
ব্রায়ান ওয়াটস

2
@ ব্রায়ান - আপনার গেটবাইআইডি সম্পর্কিত ()। আমি একটি FindById <টি, টিআইডি> (টিআইডি আইডি) ব্যবহার করি; ফলস্বরূপ যেমন ফাইন্ডবাইআইডি <ইনভয়েস, ইন্ট> (435);
জোশুয়া হেইস

আমি সাধারণভাবে স্পষ্টতই জেনেরিক ইন্টারফেসগুলিতে ফিল্ড-স্তরের ক্যোয়ারী পদ্ধতি রাখি না। যেমনটি আপনি উল্লেখ করেছেন, সমস্ত মডেলগুলিকে একটি একক কী দ্বারা অনুসন্ধান করা উচিত নয় এবং কিছু ক্ষেত্রে আপনার অ্যাপ্লিকেশন কোনও আইডি দিয়ে কোনও কিছু পুনরুদ্ধার করতে পারে না (উদাহরণস্বরূপ যদি আপনি ডিবি-উত্পাদিত প্রাথমিক কীগুলি ব্যবহার করেন এবং আপনি কেবল এগুলি পান একটি প্রাকৃতিক কী, উদাহরণস্বরূপ লগইন নাম)। পুনরায় চুলক দেওয়ার অংশ হিসাবে আমি যে নির্দিষ্ট ইন্টারফেসগুলি তৈরি করি তাতে ক্যোয়ারির পদ্ধতিগুলি বিকশিত হয়।
পল

13

আমি সুনির্দিষ্ট সংগ্রহস্থলগুলিকে পছন্দ করি যা জেনেরিক সংগ্রহস্থল (বা জেনেরিক সংগ্রহের তালিকা সঠিক আচরণ নির্দিষ্টকরণের জন্য) ওভারডেয়েবল পদ্ধতিতে স্বাক্ষর সহ প্রাপ্ত prefer


আপনি দয়া করে একটি ছোট স্নিপেট-ইশ উদাহরণ প্রদান করতে পারেন?
জোহান জেরেল

@ জোহান জেরেল না, কারণ আমি আর স্টোর ব্যবহার করি না।
আরনিস ল্যাপসা

আপনি এখন কী ব্যবহার করবেন যে আপনি সংগ্রহশালা থেকে দূরে থাকবেন?
ক্রিস

@ ক্রিস আমি সমৃদ্ধ ডোমেন মডেল রাখার বিষয়ে বেশি মনোযোগ দিই। অ্যাপ্লিকেশন ইনপুট অংশ গুরুত্বপূর্ণ কি। যদি সমস্ত রাজ্যের পরিবর্তনগুলি সাবধানতার সাথে পর্যবেক্ষণ করা হয় তবে আপনি যতক্ষণ ডেটা পড়বেন ততক্ষণ তা যথেষ্ট কার্যকর নয়। সুতরাং আমি সরাসরি NHibernate আইসেশন ব্যবহার করি। সংগ্রহস্থল স্তর বিমূর্ততা ব্যতীত আগ্রহী লোডিং, মাল্টি কোয়েরি ইত্যাদির মতো জিনিস নির্দিষ্ট করা অনেক সহজ এবং যদি আপনার সত্যিই প্রয়োজন হয় তবে আইসেশনকেও উপহাস করা শক্ত নয়।
অ্যারিস ল্যাপসা

3
@ জেসে ওয়েবেব নাহ ... সমৃদ্ধ ডোমেনের মডেল ক্যোয়ারির যুক্তিটি উল্লেখযোগ্যভাবে সরল হয়ে উঠেছে। উদাহরণস্বরূপ, যদি আমি কিছু ক্রয় করা ব্যবহারকারীদের সন্ধান করতে চাই তবে আমি কেবল ব্যবহারকারীদের জন্য অনুসন্ধান করি users যেখানে ব্যবহারকারীদের পরিবর্তে (u => u.HasPurchasedAnything ).জয়াইন (x => আদেশ, কিছু কিছু, আমি লিনক জানি না) here যেখানে ( অর্ডার => অর্ডার। স্ট্যাটাস == 1) .জায়েন (x => x. প্রোডাক্টস)। কোথায় (এক্স .... ইত্যাদি ইত্যাদি .... ব্লা ব্লাহ ব্লাহ
অরণিস ল্যাপসা

5

একটি জেনেরিক সংগ্রহস্থল রয়েছে যা একটি নির্দিষ্ট সংগ্রহস্থল দ্বারা আবৃত থাকে। আপনি পাবলিক ইন্টারফেস নিয়ন্ত্রণ করতে পারেন তবে কোড-পুনঃব্যবহারের সুবিধা রয়েছে যা জেনেরিক সংগ্রহস্থল থেকে আসে।


2

পাবলিক ক্লাসের ইউজাররোপোসিটোরি: রিপোজিটরি, আইউজারেরোপোসিটোরি

ইন্টারফেসটি প্রকাশ করা এড়াতে আপনার IUserRepository ইনজেকশন করা উচিত নয়। লোকেরা যেমন বলেছে, আপনার সম্পূর্ণ সিআরইউডি স্ট্যাকের প্রয়োজন পড়বে না etc.


2
এটি উত্তরের চেয়ে কমেন্টের মতো মনে হচ্ছে।
অমিত জোশী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.