سؤال

أقوم حاليا بإنشاء مشروع جديد، واجهت بعض الأشياء، حيث أحتاج إلى القليل من الإدخال.

هذا هو ما أفكر فيه:

  • أود مستودع عام

  • لا أريد إرجاع Iqueryable من مستودعي.

  • أود تثبيت استفساراتي في المواصفات.

  • لقد قمت بتنفيذ نمط المواصفات

  • يجب أن يكون قادرا بسهولة

الآن هذا هو المكان الذي أحصل فيه على عالقة قليلا وسأتي هو الطريقة التي ستكون الطريقة الأكثر أناقة لاستدعاء طريقة البحث مع واحد أو أكثر من المواصفات:

(طلِق): bannerRepository.Find().IsAvailableForFrontend().IsSmallMediaBanner()

أو التعبير عن الاستفسارات كما lambdas مع مواصفاتي

(لامدا): bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

أو ربما بعض طريقة أخرى تماما؟ أهم شيء هو أن الرجل الذي ينفذ جبهة MVC، يجب أن يكون لديه خبرة بديهية جيدة في المستودع.

ما آمل أن أحققه هو الحفاظ على مرونة سوم فيما يتعلق بالقدرة على الجمع بين المواصفات، وإعطاء تجربة "تصفية" مع التعويض، ولكن دون تسرب IQueryable إلى وحدة التحكم، ولكن أكثر مثل ISPecifiable، يسمح فقط لتعديل الاستعلام مع المواصفات وليس مع LinQ. ولكن هل أنا فقط مرة أخرى في تسرب المنطق الاستعلام إلى وحدة تحكم بهذه الطريقة؟

هل كانت مفيدة؟

المحلول

لقد رأيت بعض API بطلاقة يستخدم خصائص المواصفات، لذلك لا يضيفون ضجيج الأقواس إلى العملاء.

bannerRepository.Find.IsAvailableForFrontend.IsSmallMediaBanner.Exec()

كونه exec () طريقة لتنفيذ المواصفات ضد الريبو.

ولكن حتى لو كنت لا تستخدم الخصائص، أود أن أذهب للحصول على API بطلاقة، لأنه يحتوي على الحد الأدنى من الضوضاء.

نصائح أخرى

أو ربما بعض طريقة أخرى تماما؟

حسنا، في الواقع لا أحصل على تنفيذ مستودعك بالضبط (على سبيل المثال .Find() العودة؟)، لكنني سأختار اتجاه آخر:

public class Foo 
{ 
    public Int32 Seed { get; set; }
}

public interface ISpecification<T> 
{
    bool IsSatisfiedBy(T item);
}

public interface IFooSpecification : ISpecification<Foo> 
{
    T Accept<T>(IFooSpecificationVisitor<T> visitor);
}

public class SeedGreaterThanSpecification : IFooSpecification
{
    public SeedGreaterThanSpecification(int threshold)
    {
        this.Threshold = threshold;
    }
    public Int32 Threshold { get; private set; }
    public bool IsSatisfiedBy(Foo item) 
    {
        return item.Seed > this.Threshold ;
    }
    public T Accept<T>(IFooSpecificationVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}
public interface IFooSpecificationVisitor<T>
{
    T Visit(SeedGreaterThanSpecification acceptor);
    T Visit(SomeOtherKindOfSpecification acceptor);
    ...
}
public interface IFooRepository 
{
    IEnumerable<Foo> Select(IFooSpecification specification);
}
public interface ISqlFooSpecificationVisitor : IFooSpecificationVisitor<String> { }
public class SqlFooSpecificationVisitor : ISqlFooSpecificationVisitor
{
    public string Visit(SeedGreaterThanSpecification acceptor)
    {
        return "Seed > " + acceptor.Threshold.ToString();
    }
    ...
}
public class FooRepository
{   
    private ISqlFooSpecificationVisitor visitor;

    public FooRepository(ISqlFooSpecificationVisitor visitor)
    {
        this.visitor = visitor;
    }

    public IEnumerable<Foo> Select(IFooSpecification specification)
    {
        string sql = "SELECT * FROM Foo WHERE " + specification.Accept(this.visitor);
        return this.DoSelect(sql);
    }

    private IEnumerable<Foo> DoSelect(string sql)
    {
        //perform the actual selection;
    }
}

لذلك لدي كيان، واجهة مواصفاتها والعديد من المنفذين المشاركين في نمط الزائر، وواجهة مستودعها تقبل واجهة المواصفات وتنفيذ مستودعها، وقبول الزائر القادر على ترجمة المواصفات إلى بنود SQL (ولكن الأمر مجرد مسألة هذه حالة، بالطبع). أخيرا، أود أن يؤلف مواصفات "خارج" واجهة المستودع (باستخدام واجهة بطلاقة).

ربما تكون هذه مجرد فكرة ساذجة، لكنني أجدها واضحة تماما. أتمنى أن يساعدك هذا.

شخصيا سأذهب مع طريقة لامدا. قد يكون بسبب حبي لامدا لكنه يوفر مساحة كبيرة لإعداد مستودع عام.

النظر فيما يلي:

bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

لا أعرف ما يبدو أن نمطك ولكنك يمكن أن تعيد عداء بعض الأشياء هنا:

قم بإنشاء واجهة عامة تسمى "Ilepository" من النوع الذي يحتوي على جميع طرق الوصول إلى البيانات.

يمكن أن تبدو مثل هذا:

interface IRepository<T> where T : class
{
    IEnumerable<T> FindAll(Func<T, bool> exp);

    T FindSingle(Func<T, bool> exp);
}   

قم بإنشاء فئة "مستودع" مجردة تنفيذ هذه الواجهة:

class Repository<T> : IRepository<T> where T : class
{
    TestDataContext _dataContext = TestDataContext();

    public IEnumerable<T> FindAll(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Where<T>(exp);
    }

    public T FindSingle(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Single(exp);
    }
}

يمكننا الآن إنشاء واجهة لجدول / كائنات لافتات التي تنفذ "Ileposiory" وطبقة ملموسة تمدد فئة "مستودع" مجردة وتنفيذ "ibannerInterface":

interface IBannerRepository : IRepository<Banner>
{
}

ومستودع المطابقة لتنفيذها:

class BannerRepository : Repository<Banner>, IBannerRepository
{
}

أود أن أقترح استخدام هذا النهج لأنه يمنحك الكثير من المرونة وكذلك القوة الكافية للسيطرة على جميع الكيانات الصغيرة لديك.

ستكون الدعوة في هذه الأساليب سهلة للغاية بهذه الطريقة:

BannerRepository _repo = new BannerRepository();

_repo.FindSingle(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner);

نعم، هذا يعني أنه عليك القيام ببعض العمل ولكنه من الأسهل عليك تغيير مصدر البيانات لاحقا.

آمل أن يساعد!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top