2009-02-08 14 views
9

मेरे पास उत्पादों (कपड़ों) की सूची के साथ एक डेटाबेस तालिका है। उत्पाद श्रेणियों से संबंधित हैं और विभिन्न दुकानों से हैं।फ़िल्टरिंग क्वेरी के लिए उपयोग करने के लिए कौन सा डिज़ाइन पैटर्न? सी #

नमूना विभाग: टॉप, नीचे, जूते

नमूना भंडार: gap.com, macys.com, target.com

मेरे ग्राहकों को निम्न तरीकों से उत्पादों फिल्टर करने के लिए अनुरोध कर सकते हैं:

  • सभी उत्पादों (कोई फिल्टर)
  • श्रेणी के द्वारा
  • दुकान से
  • श्रेणी और स्टोर

अभी मेरे पास मेरे "उत्पाद" वर्ग में एक विधि है जो उपयोगकर्ता द्वारा अनुरोध किए गए फ़िल्टर के प्रकार के आधार पर उत्पाद लौटाती है। मैं यह निर्धारित करने के लिए फ़िल्टरबै एनम का उपयोग करता हूं कि कौन से उत्पादों को वापस करने की आवश्यकता है।

उदाहरण के लिए, उपयोगकर्ता "सबसे ऊपर" श्रेणी में सभी उत्पादों को देखने के लिए करना चाहता है, तो मैं इस समारोह फोन:

Products.GetProducts(FilterBy.Category, "tops", ""); 

मैं पिछले पैरामीटर खाली है, क्योंकि यह स्ट्रिंग है जो करने के लिए "स्टोर" शामिल है फ़िल्टर करें लेकिन इस मामले में कोई स्टोर नहीं है।

Product.GetProducts(FilterBy.CategoryAndStore, "tops", "macys.com"); 

मेरा प्रश्न है, क्या यह करने के लिए एक बेहतर तरीका है: हालांकि, अगर उपयोगकर्ता श्रेणी और दुकान के आधार पर फ़िल्टर करना चाहता है मैं विधि इस तरह से फोन होगा? मैंने अभी रणनीति डिजाइन पैटर्न के बारे में सीखा है। क्या मैं इसका उपयोग बेहतर (आसान करने के लिए आसान और बनाए रखने में आसान) तरीके से करने के लिए कर सकता हूं?

कारण मैं इस सवाल पूछ रहा हूँ है, क्योंकि मैं समझ यह एक बहुत ही आम समस्या है कि लोगों को बार-बार (विभिन्न तरीकों से छानने उत्पादों) को हल करते हैं

+0

[उदाहरण के साथ फ़िल्टर डिजाइन पैटर्न] (http://www.singhajit.com/filter-design-pattern/) –

उत्तर

13

एरिक इवान के "डोमेन ड्राइव डिज़ाइन" के अनुसार आपको विनिर्देश पैटर्न की आवश्यकता है। कुछ इस तरह

public interface ISpecification<T> 
{ 
    bool Matches(T instance); 
    string GetSql(); 
} 

public class ProductCategoryNameSpecification : ISpecification<Product> 
{ 
    readonly string CategoryName; 
    public ProductCategoryNameSpecification(string categoryName) 
    { 
    CategoryName = categoryName; 
    } 

    public bool Matches(Product instance) 
    { 
    return instance.Category.Name == CategoryName; 
    } 

    public string GetSql() 
    { 
    return "CategoryName like '" + { escaped CategoryName } + "'"; 
    } 
} 

आपका भंडार अब विनिर्देशों

var specifications = new List<ISpecification<Product>>(); 
specifications.Add(
new ProductCategoryNameSpecification("Tops")); 
specifications.Add(
new ProductColorSpecification("Blue")); 

var products = ProductRepository.GetBySpecifications(specifications); 

तुम भी एक सामान्य CompositeSpecification वर्ग जो उप विनिर्देशों और एक संकेतक जो तार्किक ऑपरेटर के रूप में उन्हें लागू करने के लिए करने के लिए होते हैं बना सकते हैं के साथ कहा जा सकता है और/या

हालांकि मैं LINQ अभिव्यक्तियों को गठबंधन करने के इच्छुक हूं।

अपडेट - क्रम

var product = Expression.Parameter(typeof(Product), "product"); 
var categoryNameExpression = Expression.Equal(
    Expression.Property(product, "CategoryName"), 
    Expression.Constant("Tops")); 

में LINQ का उदाहरण आपको एक "और" इतनी तरह

var colorExpression = Expression.Equal(
    Expression.Property(product, "Color"), 
    Expression.Constant("Red")); 
var andExpression = Expression.And(categoryNameExpression, colorExpression); 

अंत में आप एक विधेय में इस अभिव्यक्ति में बदल सकते हैं और फिर इसे अमल में जोड़ सकते हैं। ..

var predicate = 
    (Func<Product, bool>)Expression.Lambda(andExpression, product).Compile(); 
var query = Enumerable.Where(YourDataContext.Products, predicate); 

foreach(Product currentProduct in query) 
    meh(currentProduct); 

शायद संकलित नहीं होगा क्योंकि मैं इसे सीधे ब्राउज़र में टाइप किया है, लेकिन मेरा मानना ​​है कि यह आम तौर पर सही है।

कोई अन्य अपडेट :-)

List<Product> products = new List<Product>(); 
products.Add(new Product { CategoryName = "Tops", Color = "Red" }); 
products.Add(new Product { CategoryName = "Tops", Color = "Gree" }); 
products.Add(new Product { CategoryName = "Trousers", Color = "Red" }); 
var query = (IEnumerable<Product>)products; 
query = query.Where(p => p.CategoryName == "Tops"); 
query = query.Where(p => p.Color == "Red"); 
foreach (Product p in query) 
    Console.WriteLine(p.CategoryName + "/" + p.Color); 
Console.ReadLine(); 

इस मामले आप स्मृति में मूल्यांकन कर दी जाएगी, क्योंकि स्रोत एक सूची है, लेकिन अगर अपने स्रोत एक डेटा संदर्भ है कि उदाहरण के लिए मुझे लगता है कि Linq2SQL का समर्थन किया था यह एसक्यूएल का उपयोग करके मूल्यांकन करेगा।

आपकी अवधारणाओं को स्पष्ट करने के लिए आप अभी भी विशिष्टता पैटर्न का उपयोग कर सकते हैं।

public class Specification<T> 
{ 
    IEnumerable<T> AppendToQuery(IEnumerable<T> query); 
} 

दो दृष्टिकोण के बीच मुख्य अंतर (जैसे एक्सएमएल से पूरी तरह से एक प्रश्न के निर्माण के रूप में कि बाद, स्पष्ट गुणों के आधार पर एक ज्ञात क्वेरी बनाता है, जबकि पहले एक किसी भी संरचना के एक प्रश्न के निर्माण के लिए इस्तेमाल किया जा सकता है उदाहरण के लिए।)

यह आपको :-)

+0

क्या आप मुझे LINQ अभिव्यक्तियों को जोड़ने का एक उदाहरण दिखा सकते हैं? –

+0

आपके लिए एक उदाहरण जोड़ा गया, एक नज़र डालें और देखें कि आप कैसे चलते हैं। –

2

रणनीति पैटर्न जरूरी साथ अच्छी तरह से बुनी नहीं करता होना चाहिए सामान्य इंटरफ़ेस-आधारित भंडार दृष्टिकोण। व्यक्तिगत रूप से, मैं शायद जाना चाहते हैं यहाँ दो तरह से:

  • एक खोज विधि है कि विकल्प के संयोजन का समर्थन करता है:

    IList<Product> GetProducts(string category, string store, ...);

(तो चुनिंदा संयोजनों की लागू फ़िल्टर (यानी null का मतलब है "कोई भी") - या तो कमांड बनाने के दौरान, या एक एसपीआरओसी को पास करें जो कुछ समान करता है।

  • LINQ के साथ, शायद एक अनुमानित अभिव्यक्ति?

    IList<Product> GetProducts(Expression<Func<Product,bool>> predicate);

बेशक

, LINQ के साथ आप कॉलर के अनुसार रचना इस्तेमाल कर सकते हैं, लेकिन उस के लिए एक बंद/पूरी तरह से परीक्षण किया भंडार लिखने के लिए कठिन है:

`IQueryable<Product> Products {get;}` 

(और कॉलर का उपयोग करें। जहां (x => x.Category == "foo")) - मुझे इस आखिरी एक लंबी अवधि के बारे में इतना यकीन नहीं है ...

+0

विधेय रूप वास्तव में क्या है मैं पोस्ट किया है। यह बहुत लचीला है, और लैम्ब्डा अभिव्यक्तियों के साथ यह किसी भी अन्य तरीके के रूप में संक्षिप्त है। –

+0

दरअसल; और अभिव्यक्ति <...> होने पर इसे ऑब्जेक्ट-आधारित रिपॉजिटरीज़ के साथ उपयोग करने के लिए संकलित किया जा सकता है। नकारात्मकता यह है कि अभी भी LOLA को असमर्थित क्वेरी ऑपरेशंस का जोखिम है ... –

+0

* सिद्धांत * में मुझे IQueryable (वापसी) विकल्प पसंद है, लेकिन यह यूआई से डीएएल को अलग करना मुश्किल बनाता है (यानी डेटा एक्सेस करते समय गारंटी शुरू होता है और समाप्त होता है) - लेकिन यह अभी भी कुछ secnarios के लिए एक व्यवहार्य विकल्प है। –

0

मैं अपने छोटे ज्ञान के आधार पर इसका उत्तर दे रहा हूं पैटर्न के।

डेकोरेटर पैटर्न यहाँ मदद (आप & परिणाम प्राप्त एक फिल्टर जोड़ सकते हैं पर विचार। उस पर नए फ़िल्टर लागू & नए परिणाम प्राप्त) हो सकता है

1

मुझे लगता है कि मैं कोई श्रेणी वर्ग और एक स्टोर वर्ग बनाने चाहते हैं, के बजाय बस तार:

class Category 
{ 
    public Category(string s) 
    { 
    ... 
    } 
    ... 
} 

और फिर शायद:

Product.GetProducts(
    Category category, //if this is null then don't filter on category 
    Store store //if this is null then don't filter on store 
) 
{ 
    ... 
} 

Category और Store कक्षाएं संबंधित हो सकती हैं (वे दोनों Filter कक्षा के उप-वर्ग हो सकते हैं)।

0

मैं खुद को फिल्टर के लिए एक रणनीति की तरह कुछ के साथ जाने के लिए और CategoryFilter और StoreFilter कक्षाएं लिखेंगे। फिर मैं फ़िल्टर को गठबंधन करने के लिए एक समग्र या सजावटी का उपयोग करूंगा।

0

शुरू कर दिया तुम सिर्फ इसे नहीं जोड़ सकते कहाँ सामान के रूप में आप यहां जा करने के लिए पर्याप्त होना चाहिए?

var products = datacontext.Products; 

if(!String.IsNullOrEmpty(type)) 
    products = products.Where(p => p.Type == type); 

if(!String.IsNullOrEmpty(store)) 
    products = products.Where(p => p.Store == store); 

foreach(var p in products) 
    // Do whatever 

या कुछ इस तरह ...

संबंधित मुद्दे

 संबंधित मुद्दे