ওআরএম লজিকের এনক্যাপসুলেটিংয়ের জন্য সংগ্রহস্থলের প্যাটার্নের বিকল্প?


24

আমাকে কেবল একটি ওআরএম পরিবর্তন করতে হয়েছিল এবং এটি একটি তুলনামূলকভাবে কঠিন কাজ ছিল কারণ ক্যোয়ারী যুক্তিটি সর্বত্র ফাঁস হয়ে যাচ্ছিল। যদি আমাকে কোনও নতুন অ্যাপ্লিকেশন বিকাশ করতে হয় তবে আমার ব্যক্তিগত পছন্দটি হ'ল পরিবর্তনের জন্য ভবিষ্যতের প্রতিরোধে সমস্ত ক্যোয়ারী যুক্তি (একটি ওআরএম ব্যবহার করে) সজ্জিত করা। কোড এবং রক্ষণাবেক্ষণের জন্য সংগ্রহস্থল প্যাটার্নটি বেশ ঝামেলাযুক্ত তাই আমি ভাবছিলাম যে সমস্যার সমাধান করার জন্য অন্য কোনও নিদর্শন আছে কিনা?

অতিরিক্ত জটিলতা না দেওয়ার বিষয়ে পোস্টগুলি আগে থেকেই জানতে পারি এটির প্রয়োজনের আগে, চটপটে হওয়া ইত্যাদি but তবে আমি কেবল বিদ্যমান প্যাটার্নগুলি সম্পর্কে একটি সরল উপায়ে অনুরূপ সমস্যা সমাধানের বিষয়ে আগ্রহী।

আমার প্রথম চিন্তা ছিল জেনেরিক টাইপ সংগ্রহস্থল, যা আমি বর্ধিত পদ্ধতির মাধ্যমে নির্দিষ্ট ধরণের সংগ্রহস্থল শ্রেণীর জন্য প্রয়োজনীয় পদ্ধতিগুলি যুক্ত করি, তবে ইউনিট টেস্টিং স্ট্যাটিক পদ্ধতিগুলি অত্যন্ত বেদনাদায়ক। অর্থাৎ,

public static class PersonExtensions
{
    public static IEnumerable<Person> GetRetiredPeople(this IRepository<Person> personRep)
    {
        // logic
    }
}

5
আপনি কোড এবং রক্ষণাবেক্ষণ করতে অসুবিধাজনক মনে করেন এমন সংগ্রহস্থল প্যাটার্নটি সম্পর্কে ঠিক কী?
ম্যাথু ফ্লিন

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

উত্তর:


14

প্রথমত: একটি জেনেরিক সংগ্রহস্থলকে বেস ক্লাস হিসাবে বিবেচনা করা উচিত এবং সম্পূর্ণ বাস্তবায়ন নয়। এটি আপনাকে সাধারণ CRUD পদ্ধতিগুলি পেতে সহায়তা করবে to তবে আপনাকে এখনও কোয়েরি পদ্ধতিগুলি প্রয়োগ করতে হবে:

public class UserRepository : EntityFrameworkRepository<User>, IUserRepository
{
    public UserRepository(DbContext context){}

    public ICollection<Person> FindRetired()
    {
        return context.Persons.Where(p => p.Status == "Retired").ToList();
    }
}

দ্বিতীয়ত:

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

বিকল্প

বিকল্প হিসাবে আপনি প্রশ্নগুলি ব্যবহার করতে পারেন (উদাহরণস্বরূপ কমান্ড / ক্যোয়ারী বিচ্ছেদ প্যাটার্ন দ্বারা সংজ্ঞায়িত)। উইকিপিডিয়াতে সিকিউএস বর্ণিত হয়েছে।

আপনি মূলত ক্যোয়ারী ক্লাস তৈরি করেন যা আপনি প্রার্থনা করেন:

public class GetMyMessages
{
    public GetMyMessages(IDbConnection connection)
    {
    }


    public Message[] Execute(DateTime minDate)
    {
        //query
    }
}

প্রশ্নের সাথে দুর্দান্ত জিনিস হ'ল আপনি কোডটি বিশৃঙ্খলা ছাড়াই বিভিন্ন প্রশ্নের জন্য বিভিন্ন ডেটা অ্যাক্সেস পদ্ধতি ব্যবহার করতে পারেন। আপনি উদাহরণস্বরূপ একটিতে একটি ওয়েব পরিষেবা, অন্যটিতে নিবারনেট এবং তৃতীয় অংশে ADO.NET ব্যবহার করতে পারেন।

আপনি যদি নেট রূপায়ণে আগ্রহী হন তবে আমার নিবন্ধটি পড়ুন: http://blog.gauffin.org/2012/10/griffin-decoupled-the-queries/


বিকল্প প্যাটার্নটি কী আপনি বড় প্রকল্পগুলিতে আরও বিশৃঙ্খলা তৈরি করার পরামর্শ দিয়েছিলেন তা দেখবেন না যে रिपোটারি প্যাটার্নে এখন কীভাবে একটি সম্পূর্ণ শ্রেণি রয়েছে?
দান্তে

3
আপনার যদি ছোট ক্লাস থাকার সংজ্ঞা বিশৃঙ্খলা হয়, তবে হ্যাঁ। সেক্ষেত্রে আপনার সলিড নীতি অনুসরণ করার চেষ্টা করা উচিত নয় কারণ এগুলি প্রয়োগ করা সবসময় আরও বেশি (ছোট) শ্রেণি তৈরি করে।
jgauffin

2
ছোট ক্লাসগুলি আরও ভাল, তবে কী (ক্লায়েন্ট) রিপোজিটরির ইন্টেলিজেন্স ব্রাউজ করে এটি দেখার চেয়ে বিদ্যমান কোয়েরি ক্লাসগুলির নেভিগেশনটি আরও বেশি সমস্যাজনক হবে না, যদি প্রয়োজনীয় কার্যকারিতা সেখানে থাকে এবং যদি না থাকে তবে এটি প্রয়োগ করুন।
দান্তে

4
প্রকল্পের কাঠামো আরও গুরুত্বপূর্ণ হয়ে ওঠে। আপনি যদি এমন সমস্ত নাম একটি নেমস্পেসে রাখেন তবে YourProject.YourDomainModelName.Queriesনেভিগেট করা সহজ হবে।
jgauffin

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

8

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

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

আমি যদি এই জাতীয় বিমূর্ততা তৈরি করতে চাই, তবে আমি এই বিধিগুলি / নিদর্শনগুলি ব্যবহার করব

  • CQRS
  • বিদ্যমান ওআরএম বৈশিষ্ট্যগুলি যতটা সম্ভব ব্যবহার করুন
  • কেবল জটিল যুক্তি এবং কোয়েরিগুলি সজ্জিত করে
  • কোনও স্থাপত্যের অভ্যন্তরে ORM এর "নদীর গভীরতানির্ণয়" লুকানোর চেষ্টা করুন

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

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

প্রস্তাবিত পাঠ হিসাবে, আমি আইয়েন্দির ব্লগটি বিশেষত এই নিবন্ধটি বলব ।


+1 টি মুনাফা "গত জিনিস আমি বলতে চাই, অনেকে এটি কিভাবে ব্যবহার করতে বুদ্ধিমান এবং কিভাবে ভাল করতে থাকলে ORM ব্যবহার" "এটা আউট ভান্ডার সুপারিশ লোকেরা এই ধরনের সাধারণত আছে।"
Misters

1

ফাঁস বাস্তবায়নের ক্ষেত্রে সমস্যাটি হ'ল আপনার অনেকগুলি ফিল্টার শর্তাদি দরকার।

আপনি যদি এপিআইটিকে সংকীর্ণ করতে পারেন যদি আপনি কোনও সংগ্রহস্থল পদ্ধতি FindByExample প্রয়োগ করেন এবং এটি এর মতো ব্যবহার করেন

// find all retired persons
Person filter = new Person {Status=PersonStatus.Retired};
IEnumerable<Person> found = personRepository.FindByExample(filter);


// find all persons who have a dog named "sam"
Person filter = new Person();
filter.AddPet(new Dog{Name="sam"});
IEnumerable<Person> found = personRepository.FindByExample(filter);

0

আপনার এক্সটেনশানগুলি আইআরপোসিটরির পরিবর্তে আইকোয়ারিযোগ্যতে পরিচালনা করা বিবেচনা করুন।

public static class PersonExtensions
{
    public static IQueryable<Person> AreRetired(this IQueryable<Person> people)
    {
        return people.Where(p => p.Status == "Retired");
    }
}

ইউনিট পরীক্ষায়:

List<Person> people = new List<Person>();
people.Add(new Person() { Name = "Bob", Status = "Retired" });
people.Add(new Person() { Name = "Sam", Status = "Working" });

var retiredPeople = people.AsQueryable().AreRetired();
// assert that Bob is in the list
// assert that Sam is not in the list

পরীক্ষার জন্য কোনও অনুরাগী উপহাসের প্রয়োজন নেই। প্রয়োজন অনুযায়ী আরও জটিল প্রশ্ন তৈরি করতে আপনি এই এক্সটেনশন পদ্ধতিগুলিও একত্রিত করতে পারেন।


5
-1 ক) IQueryableখারাপ মা, বা বরং একটি ODশ্বরের ইন্টারফেস। এটি বাস্তবায়নের ক্ষেত্রে খুব বেশি ছিল এবং স্কেল সরবরাহকারীদের কাছে খুব কম (যদি থাকে) সম্পূর্ণ লিনকিউ রয়েছে। খ) এক্সটেনশন পদ্ধতিগুলি এক্সটেনশনকে (তহবিলের অন্যতম ওওপি নীতি) অসম্ভব করে তোলে।
jgauffin

0

আমি এখানে NHibernate জন্য একটি সুন্দর ঝরঝরে ক্যোয়ারী অবজেক্ট প্যাটার্ন লিখেছি: https://github.com/shaynevanasperen/NHibernate.Sessions.Operation

এটি এর মতো ইন্টারফেস ব্যবহার করে কাজ করে:

public interface IDatabases
{
    ISessionManager SessionManager { get; }

    T Query<T>(IDatabaseQuery<T> query);
    T Query<T>(ICachedDatabaseQuery<T> query);

    void Command(IDatabaseCommand command);
    T Command<T>(IDatabaseCommand<T> command);
}

এটির মতো একটি পোকো সত্তা শ্রেণি দেওয়া হয়েছে:

class Database1Poco
{
    public int Property1 { get; set; }
    public string Property2 { get; set; }
}

আপনি এর মতো ক্যোয়ারী অবজেক্টগুলি তৈরি করতে পারেন:

class Database1PocoByProperty1 : DatabaseQuery<Database1Poco>
{
    public override Database1Poco Execute(ISessionManager sessionManager)
    {
        return sessionManager.Session.Query<Database1Poco>().SingleOrDefault(x => x.Property1 == Property1);
    }

    public int Property1 { get; set; }
}

এবং তারপরে এগুলি ব্যবহার করুন:

var database1Poco = _databases.Query(new Database1PocoByProperty1 { Property1 = 1 });

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

আমার ক্ষমাপ্রার্থী, আমি তাড়াতাড়ি ছিলাম। কিছু উদাহরণ কোড দেখানোর জন্য উত্তর আপডেট হয়েছে।
শায়নে

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