2013-08-05 7 views
5

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

public class DBQuerier<T> 
    where T : class 
{ 
    DbSet<T> relation; 

    public DBQuerier(DbSet<T> table) 
    { 
     relation = table; 
    } 

    public bool Exists(T toCheck); 
    public void Add(T toAdd); 
    public T (Get Dictionary<String, Object> fields); 
    public bool SubmitChanges(); 
    public void Update(T toUpdate, Dictionary<String, Object> fields); 
    public void Delete(T toDelete); 
} 

मेरे समस्या पहले बाधा पर आता है जब अगर एक रिकार्ड मौजूद है देखने के लिए जाँच करने की कोशिश कर क्योंकि मैं सामान्य प्रकार टी और एक ऑब्जेक्ट प्रकार के बीच परिवर्तित नहीं कर सकता जिसे मैं काम करने की कोशिश कर रहा हूं।

public bool Exists(T toCheck) 
{ 
    return (from row in relation 
     where row.Equals(toCheck) 
     select row).Any(); 
} 

एक रन-टाइम अपवाद तब होता है के रूप में एसक्यूएल कुछ भी लेकिन आदिम प्रकार के साथ काम नहीं कर सकते हैं, भले ही मैं IComparable को लागू करने और अपने खुद के बराबर है कि एक ही क्षेत्र तुलना नामित: यदि मैं आधार Linq का उपयोग करें। लैम्ब्डा भाव करीब आने लगते हैं, लेकिन फिर मैं भले ही मेरी समझ गया था कि Expression.Equal यह वर्ग 'तुलनीय समारोह का उपयोग करने के लिए मजबूर एसक्यूएल आदिम प्रकार की तुलना में अधिक को संभालने में सक्षम नहीं किया जा रहा के साथ फिर से समस्याओं मिलती है:

public bool Exists(T toCheck) 
{ 
    ParameterExpression T1 = Expression.Parameter(typeof(myType), "T1"); 
    ParameterExpression T2 = Expression.Parameter(typeof(myType), "T2"); 
    BinaryExpression compare = Expression.Equal(T1, T2); 
    Func<T, T, bool> checker = 
     Expression.Lambda<Func<T, T, bool>> 
      (compare, new ParameterExpression[] { T1, T2 }).Compile(); 
    return relation.Where(r => checker.Invoke(r, toCheck)).Any(); 
} 

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

+0

नोट अपने 'Exists' विधि सिर्फ एक नाम दिया' एक कार्यान्वयन के रूप में अच्छा के बिना Contains' तरीका है। – Servy

+0

आप एक प्राथमिक कुंजी स्तंभ तुम हमेशा यदि वह मौजूद है की जाँच करने के 'relation.Find (आईडी)' विधि का उपयोग कर सकते हैं। – Nilesh

उत्तर

2

इकाई की रूपरेखा है अपने कस्टम LINQ के साथ काम करने की संभावना नहीं कर सकते हैं, यह आदेश होते हैं जो इसका समर्थन करता है में काफी कठोर है। मैं थोड़ा सा रैमबल करने जा रहा हूं और यह छद्म कोड है, लेकिन मुझे दो समाधान मिले जो मेरे लिए काम करते थे।

मैंने पहली बार जेनेरिक दृष्टिकोण का उपयोग किया, जहां मेरा जेनेरिक डेटाबेस खोजकर्ता Func<T, string> nameProperty को उस नाम तक पहुंचने के लिए स्वीकार करेगा जो मैं पूछताछ करने जा रहा था। ईएफ में सेट और गुणों तक पहुंचने के लिए कई ओवरलोड हैं, इसलिए मैं c => c.CatName में गुजरकर और जेनेरिक फैशन में संपत्ति तक पहुंचने के लिए इसका उपयोग कर सकता हूं। हालांकि यह थोड़ा गंदा था, तो:

मैं बाद में इस पुनर्संशोधित इंटरफेस का उपयोग करने के।

मैं एक समारोह है कि किसी भी तालिका/स्तंभ आप विधि में पारित पर एक पाठ खोज करता है।

मैं एक अंतरफलक INameSearchable कहा जाता है जो केवल एक संपत्ति है कि खोज करने के लिए नाम संपत्ति हो जाएगा शामिल बनाया। मैं तो मेरे इकाई वस्तुओं (वे आंशिक वर्गों रहे हैं) बढ़ाया INameSearchable लागू करने के लिए। इसलिए मैं Cat नामक संस्था है जो एक CatName संपत्ति है की है। मैं इंटरफेस का नाम संपत्ति के रूप में return CatName; के लिए इंटरफ़ेस का इस्तेमाल किया।

मैं फिर एक सामान्य खोज विधि where T : INameSearchable बना सकता हूं और यह Name संपत्ति का खुलासा करेगा जो मेरा इंटरफ़ेस खुलासा हुआ है। मैं फिर क्वेरी को निष्पादित करने के लिए बस अपनी विधि में इसका उपयोग करता हूं, उदाहरण के लिए। (स्मृति से स्यूडोकोड!)

doSearch(myContext.Cats);

और विधि

public IEnumerable<T> DoSearch<T>(IDbSet<T> mySet, string catName) 
{ 
    return mySet.Where(c => c.Name == catName); 
} 

और काफी खूबसूरती से में, यह मेरे सामान्य रूप से कुछ भी खोज करने के लिए अनुमति देता है।

मुझे उम्मीद है कि इससे मदद मिलती है।

+0

मुझे आपके समाधान में रूचि है। क्या आप अपने इंटरफ़ेस पर विस्तृत करने के लिए पर्याप्त दयालु हो सकते हैं: INAMESearchable और आपने इसे कैसे कार्यान्वित किया है? मुझे लगता है कि आप ईएफ संदर्भ वर्ग का विस्तार कर रहे हैं? जो हर बार मॉडल को रीफ्रेश करते समय ओवरराइट किया जाएगा? – DaniDev

+0

हालांकि अच्छा समाधान! अधिक स्पष्ट करने के लिए थोड़ा और कोड के साथ और अधिक समझने योग्य होता। हालांकि 1 ऊपर :) – Irfan

6

इसे संकलित न करें। Func<T,bool> का अर्थ है "इसे स्मृति में चलाएं" जबकि Expression<Func<T,bool>> का अर्थ है "यह अनुमानित तर्क के बारे में तार्किक विचार रखें" जो क्वेरी फ्रेमवर्क को क्वेरी में अनुवाद करने की अनुमति देता है।

एक तरफ ध्यान दें के रूप में, मुझे नहीं लगता कि उस संस्था ढांचे आप क्वेरी करने के लिए a.Equals(b) करने की सुविधा देता है, तो आप आप उपयोग करना EntityFramework आप आदिम प्रकार का उपयोग करना होगा चाहते हैं a.Id == b.Id

0

करना होगा। कारण यह है कि आपकी LINQ-अभिव्यक्ति को SQL-कथन में परिवर्तित कर दिया गया है। एसक्यूएल वस्तुओं, IComparables बारे में कुछ पता नहीं है, ...

आप इसे की जरूरत नहीं है एसक्यूएल में होने के लिए आपको पहले एसक्यूएल के खिलाफ क्वेरी निष्पादित और फिर स्मृति में फिल्टर करने के लिए है। आपको लगता है कि तरीकों के साथ आप वर्तमान में उपयोग कर रहे हैं

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