14

मैं इकाई फ्रेमवर्क के लिए डेटा स्थानीयकरण तर्क को लागू करने की कोशिश कर रहा हूं। इसलिए यदि उदाहरण के लिए एक क्वेरी Title प्रॉपर्टी का चयन करती है, तो दृश्यों के पीछे इसे वर्तमान उपयोगकर्ता संस्कृति के आधार पर कॉलम Title_enGB या Title_deCH का संदर्भ देना चाहिए।EntityFramework क्वेरी मैनिपुलेशन, डीबी प्रदाता रैपिंग, डीबी अभिव्यक्ति पेड़

इसे प्राप्त करने के लिए, मैं एंटिटी फ्रेमवर्क से डीबीएक्सप्रेस कमांडट्री को फिर से लिखना चाहता हूं। मैंने सोचा कि trees क्रॉस डेटाबेस डालने/अद्यतन/चयन प्रश्नों के निर्माण के लिए एक नया आम .NET तरीका है .. लेकिन अब System.Data.Metadata औरमें सभी प्रासंगिक रचनाकार/कारखानों System.Data.Entity.dll आंतरिक हैं !! (एमएसडीएन में जनता के रूप में प्रलेखित, जैसे: DbExpressionBuilder)।

क्या किसी के पास क्वेरी पेड़ पुनर्लेखन के साथ या बिना इस क्वेरी मैनिपुलेशन को प्राप्त करने का कोई विचार है?

मेरी वांछित कोड: (public class DbProviderServicesWrapper : DbProviderServices)

/// <summary> 
/// Creates a command definition object for the specified provider manifest and command tree. 
/// </summary> 
/// <param name="providerManifest">Provider manifest previously retrieved from the store provider.</param> 
/// <param name="commandTree">Command tree for the statement.</param> 
/// <returns> 
/// An exectable command definition object. 
/// </returns> 
protected override DbCommandDefinition CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree) 
{ 
    var originalCommandTree = commandTree as DbQueryCommandTree; 
    if (originalCommandTree != null) 
    { 
     var expression = new MyCustomQueryRewriter(originalTree.MetadataWorkspace).Visit(originalCommandTree.Query); 
     commandTree = DbQueryCommandTree.FromValidExpression(originalCommandTree.MetadataWorkspace, originalCommandTree.DataSpace, expression); 
    } 

    // TODO: UpdateCommand/InsertCommand 

    var inner = this.Inner.CreateCommandDefinition(providerManifest, commandTree); 
    var def = new DbCommandDefinitionWrapper(inner, (c, cd) => new DbCommandWrapper(c)); 

    return def; 
} 



अद्यतन

एक मेज पर दो शीर्षक कॉलम होने शांत नहीं है, लेकिन इसकी आसान एक पहला कदम में लागू करने के लिए । बाद में मैं स्थानीय फ़ील्ड के साथ एक अन्य तालिका में शामिल हो जाऊंगा, इसलिए मुख्य तालिका में केवल परिवर्तनीय डेटा होगा।

Multilanguage

+1

दो संस्कृति-निर्भर मुद्दे हैं जिन्हें आप अपने स्थानीयकरण से अनदेखा कर रहे हैं। (1) कीमत अमेरिकी मुद्रा में व्यक्त की जाती है। (2) मात्रा मीट्रिक प्रणाली में व्यक्त की जाती है। – smartcaveman

उत्तर

5

.net में आप स्थानीयकरण से निपटने के लिए resx फ़ाइलों की है। देखें: What are the benefits of resource(.resx) files?

अपने दृष्टिकोण के साथ समस्याओं के एक जोड़े हैं:

  • एक अतिरिक्त भाषा जोड़ने पर एक डेटाबेस परिवर्तन
  • डेटाबेस से आवश्यक है से अधिक डेटा यातायात है की आवश्यकता है

मुझे पता है कि यह आपके प्रश्न का सीधा जवाब नहीं है लेकिन मुझे लगता है कि आपको resx फ़ाइलों को देखना चाहिए।

  • तालिका 1:: आईडी, पाठ
  • तालिका 2: आईडी, Table1_id, LANGUAGE_CODE, पाठ

यह

आप डेटाबेस में संग्रहीत करना चाहिए तो आप डेटाबेस को नया स्वरूप सकता है जिस तरह से एक नई भाषा को डेटाबेस परिवर्तन की आवश्यकता नहीं होती है, और ईएफ कोड बहुत आसान हो जाता है।

+0

आपका सुझाव आसान है। लेकिन मैं एक इकाई फ्रेमवर्क एक्सटेंशन, लिखना चाहता हूं जो इसे स्वचालित रूप से संभाल सकता है ताकि डेवलपर्स को इन क्वेरी को मैन्युअल रूप से करने की आवश्यकता न हो, प्रत्येक क्वेरी, पर मेरी अधिकांश इकाइयों में बहुभाषी स्ट्रिंग और बाइनरी गुण होते हैं। जीनोम में, हमारे .NET 3.5 ORM (ऊपर चित्र) यह स्वचालित रूप से प्रबंधित भी किया गया था। – benwasd

+1

आप एक दृश्य बना सकते हैं और जोड़ों को –

+0

में देख सकते हैं लेकिन यह कोड फर्स्ट के साथ अच्छा नहीं खेलेंगे, या होगा? –

5

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

यदि ऐसा है, तो यह महत्वपूर्ण है कि EDMX फ़ाइल/POCO में Title_enGB/etc कॉलम मैप किए गए हों। यदि वे हैं, तो मुझे लगता है कि यह संभव है।आप यहां क्या कर सकते हैं, एक एक्सप्रेशन विज़िटर का उपयोग करें जो सदस्य एक्सपेरियंस पर जाता है, जांचता है कि क्या वे "शीर्षक" नामक एक संपत्ति तक पहुंचते हैं (आप इस तरह के इलाज के लिए आवश्यक गुणों का श्वेतसूची बना सकते हैं) और फिर एक नया सदस्य एक्स्प्रेशन वापस कर सकते हैं जो इसके बजाय एक्सेस करता है Title_enGB अगर लॉग इन उपयोगकर्ता में उस भाषा सेट है।

एक त्वरित उदाहरण:

public class MemberVisitor : ExpressionVisitor 
{ 
    protected override Expression VisitMember(MemberExpression node) 
    { 
    if(node.Member.Name == "Title") 
    { 
     return Expression.Property(node.Expression, "Title_" + User.LanguageCode) 
    } 

    return base.VisitMember(node); 
    } 
} 

और फिर इससे पहले कि आप क्वेरी निष्पादित करें:

var visitor = new MemberVisitor(); 
visitor.Visit(query); 

फिर, यह केवल एक अच्छा विचार है आप डेटाबेस किसी भी पर कोई नियंत्रण नहीं है, तो अधिक।

यह समाधान आपके सटीक परिस्थिति के आधार पर आपके लिए व्यावहारिक हो सकता है या नहीं भी हो सकता है, लेकिन अभिव्यक्तियों का उपयोग करके प्रश्नों को फिर से लिखना निश्चित रूप से संभव है।

यह एंटिटी फ्रेमवर्क वास्तविक SQL क्वेरीज कैसे उत्पन्न करता है यह संशोधित करने से यह एक उच्च स्तर का समाधान है। यह वास्तव में आपके लिए छिपा हुआ है, शायद अच्छे कारण से। इसके बजाय, आप केवल अभिव्यक्ति वृक्ष को संशोधित करते हैं जो क्वेरी का वर्णन करता है और एंटिटी फ्रेमवर्क को इसे SQL में परिवर्तित करने की चिंता करने देता है।

+0

उन दो पंक्तियों को कहां रखा जाए? var आगंतुक = नया सदस्य विजिटर(); आगंतुक। विज़िट (क्वेरी); –

1
इसके बजाय

मैं एक और डिजाइन का प्रस्ताव देगा ...

Products 
    ProductID 
    ProductName 
    Price 
    Description 
    ParentID (Nullable, FK on ProductID) 
    LangCode 

अब इस मामले में तुम हो,

1, Milk, $1 , EnglishDesc , NULL, en-us 
2. M*^*, ^*&, OtherLangDesc, 1 , @$#$$ 

आपका रिकॉर्ड 2 वास्तव में किसी अन्य भाषा की पहचान अलग भाषा में पूरे उत्पाद का वर्णन है LanguageCode द्वारा।

इस तरह आप केवल एक तालिका का प्रबंधन कर सकते हैं और कुछ जेनेरिक आधारित या प्रतिबिंब आधारित क्वेरीिंग समाधान लिखना बहुत आसान होगा।

// Get Active Products 
q = context.Products.Where(x=> x.ParentID == null); 

// Get Product's Language Code Description 
IQueryable<Product> GetProductDesc(int productID, string langCode){ 
    return context.Products.Where(x=>x.ParentID == productID && 
       x.LangCode == langCode); 
} 

आप इस प्रकार एक अंतरफलक बना सकते हैं,

interface IMultiLangObject{ 
    int? ParentID {get;set;} 
    string LangCode {get;set;} 
} 

और आप इस के आधार पर एक सामान्य समाधान लिख सकते हैं।