2012-07-27 15 views
10

मैं इस तरह एक वर्ग मिल गया है:मैं सी # में SQL क्वेरी के परिणामों से कक्षा को कैसे पॉप्युलेट कर सकता हूं?

public class Product 
{ 
    public int ProductId { get; private set; } 
    public int SupplierId { get; private set; } 

    public string Name { get; private set; } 
    public decimal Price { get; private set; } 
    public int Stock { get; private set; } 
    public int PendingStock { get; private set; } 
} 

मैं इस तरह मेरे डेटाबेस से उन विवरण लाने कर सकते हैं:

SELECT product_id, supplier_id, name, price, total_stock, pending_stock 
FROM products 
WHERE product_id = ? 

मैं स्वयं एक DataSet के माध्यम से चलाने के लिए है नहीं करना चाहती या मान सेट करने के लिए DataTable

मुझे यकीन है कि किसी प्रकार की बाध्यकारी/मैपिंग तंत्र का उपयोग करके कक्षा को पॉप्युलेट करने का एक तरीका है, लेकिन केवल एक चीज जो मुझे मिल सकती है वह Winforms घटकों या XAML का उपयोग करने के लिए बाध्यकारी थी।

वहाँ वर्ग स्वचालित रूप से एक प्रश्न पंक्ति से आबादी के लिए मैं अपने गुण/वर्ग के लिए आवेदन कर सकते हैं विशेषता किसी तरह का है?

उत्तर

10

मैंने एक और जवाब प्रस्तावित करने का निर्णय लिया है, जो वास्तव में एलेक्स द्वारा प्रदान किए गए उत्तर के लिए विस्तारित है (इसलिए उसे सभी क्रेडिट), लेकिन यह कॉलम-नाम-2-संपत्ति-नाम मैपिंग के लिए विशेषताओं को प्रस्तुत करता है।

सबसे पहले कस्टम धारण करने के लिए स्तंभ नाम की जरूरत है विशेषता:

[AttributeUsage(AttributeTargets.Property, Inherited = true)] 
[Serializable] 
public class MappingAttribute : Attribute 
{ 
    public string ColumnName = null; 
} 

विशेषता वर्ग के उन गुणों, कि डेटाबेस पंक्ति से आबादी किया जा रहे हैं करने के लिए लागू किया जाना चाहिए:

public class Product 
{ 
    [Mapping(ColumnName = "product_id")] 
    public int ProductId { get; private set; } 

    [Mapping(ColumnName = "supplier_id")] 
    public int SupplierId { get; private set; } 

    [Mapping(ColumnName = "name")] 
    public string Name { get; private set; } 
    [Mapping(ColumnName = "price")] 
    public decimal Price { get; private set; } 
    [Mapping(ColumnName = "total_stock")] 
    public int Stock { get; private set; } 
    [Mapping(ColumnName = "pending_stock")] 
    public int PendingStock { get; private set; } 
} 

और शेष एलेक्स के रूप में चला जाता है, सिवाय इसके कि विशेषता का उपयोग कॉलम नाम पुनर्प्राप्त करने के लिए किया जाता है:

T MapToClass<T>(SqlDataReader reader) where T : class 
{ 
     T returnedObject = Activator.CreateInstance<T>(); 
     PropertyInfo[] modelProperties = returnedObject.GetType().GetProperties(); 
     for (int i = 0; i < modelProperties.Length; i++) 
     { 
      MappingAttribute[] attributes = modelProperties[i].GetCustomAttributes<MappingAttribute>(true).ToArray(); 

      if (attributes.Length > 0 && attributes[0].ColumnName != null) 
       modelProperties[i].SetValue(returnedObject, Convert.ChangeType(reader[attributes[0].ColumnName], modelProperties[i].PropertyType), null); 
     } 
     return returnedObject; 
} 
+0

मैं लगभग बिल्कुल इस तरह लिख रहा था। सहायता के लिए धन्यवाद! :) – Polynomial

+0

बस याद रखें कि प्रतिबिंब मुक्त नहीं है, इसलिए कुछ लाइनों से अधिक मैपिंग करते समय कैशिंग का थोड़ा सा जरूरी हो सकता है;) – madd0

+0

मैं पूरी तरह से madd0 से सहमत हूं (मैंने अपने दूसरे उत्तर में यह कहा है)। यदि आप कोड का अत्यधिक उपयोग करना चाहते हैं - तो आपको कुछ कैशिंग प्रदान करने की आवश्यकता होगी। –

0

तो फिर तुम एसक्यूएल करने के लिए इकाई की रूपरेखा या Linq का उपयोग करना चाहिए और यदि आप न कि उपयोग करना चाहते हैं, तो आप मैप करने के लिए/भरने की जरूरत है यह आत्म इकाई की रूपरेखा पर yr

अधिक जानकारी http://msdn.microsoft.com/en-us/data/ef.aspx

अधिक Linq पर जानकारी SQL को http://msdn.microsoft.com/en-us/library/bb386976.aspx

+0

क्या आप इकाई ढांचे के लिए एक त्वरित उदाहरण प्रदान कर सकते हैं? मैंने प्रलेखन के माध्यम से फटकारा है, लेकिन यह वास्तव में इसका उपयोग करने के तरीके पर बहुत अस्पष्ट है। – Polynomial

+0

समस्या यह है कि वर्ग को इकाई से बनाया जाना है, आप इसके लिए अपनी कक्षाओं का उपयोग नहीं कर सकते हैं, और मेरे ज्ञान से मैन्युअल मैपिंग तक कनवर्ट करने का कोई स्वचालित तरीका नहीं है। – JSantos

2

मैं एसक्यूएल को Linq का उपयोग करें और के रूप में यह करना होगा इस प्रकार है:

public class Product 
{ 
    public int ProductId { get; private set; } 
    public int SupplierId { get; private set; } 
    public string Name { get; private set; } 
    public decimal Price { get; private set; } 
    public int Stock { get; private set; } 
    public int PendingStock { get; private set; } 

    public Product(int id) 
    { 
     using(var db = new MainContext()) 
     { 
      var q = (from c in product where c.ProductID = id select c).SingleOrDefault(); 
      if(q!=null) 
       LoadByRec(q);   
     } 
    } 
    public Product(product rec) 
    { 
     LoadByRec(q); 
    } 
    public void LoadByRec(product rec) 
    { 
     ProductId = rec.product_id; 
     SupplierID = rec.supplier_id; 
     Name = rec.name; 
     Price = rec.price; 
     Stock = rec.total_stock; 
     PendingStock = rec.pending_stock; 
    } 
} 
+0

क्या आप इसमें कुछ स्पष्टीकरण जोड़ सकते हैं? मुझे 'उपयोग' में कहीं भी इस्तेमाल नहीं किया जा रहा है, और क्वेरी का कोई संदर्भ नहीं है।क्या किसी विधि में मैन्युअल रूप से मैप करने के बजाय 'LoadByRec' गुणों के सेट के रूप में काम करने का कोई तरीका नहीं है? – Polynomial

+0

@ पोली आपको डेटा संदर्भ डालना होगा: http://msdn.microsoft.com/en-us/library/bb384470.aspx जो इस मामले में आप 'MainContext' नाम देंगे। निश्चित रूप से इसके साथ खेलें, यह वास्तव में वास्तव में शक्तिशाली है और डैपर के लिए –

12

आपको या तो संपत्तियों को मानचित्र करना होगा या ओआरएम (ऑब्जेक्ट रिलेशनल मैपर) का उपयोग करना होगा।

माइक्रोसॉफ्ट Entity Framework प्रदान करता है, लेकिन Dapper को कम ओवरहेड की आवश्यकता होती है और आपकी आवश्यकताओं के आधार पर एक व्यवहार्य विकल्प हो सकता है।

आपके मामले में, साफ-सुथरी कोड कुछ ऐसा दिखाई देगा:

var query = @"SELECT product_id, supplier_id, name, price, total_stock, pending_stock 
FROM products 
WHERE product_id = @id"; 

var product = connection.Query<Product>(query, new { id = 23 }); 

पूर्णता के लिए के लिए, यह है कि मैं साफ-सुथरी के बारे में यहाँ बात कर रहा हूँ बाहर बात करने के लिए महत्वपूर्ण है क्योंकि के लिए सवाल चिंताओं मानचित्रण एसक्यूएल परिणाम वस्तुओं। ईएफ और लिंक से एसक्यूएल भी ऐसा करेंगे, लेकिन वे अतिरिक्त सामान भी करेंगे, जैसे कि लिंक कथन को SQL कथन में अनुवाद करना, जो उपयोगी भी हो सकता है।

+2

+1 –

1

कच्चे .नेट फ्रेमवर्क में डिफ़ॉल्ट रूप से ऐसी कोई कार्यक्षमता नहीं है। आप इकाई फ्रेमवर्क का उपयोग कर सकते हैं, लेकिन यदि यह आपके लिए अच्छा समाधान नहीं है, तो एक विकल्प प्रतिबिंब तंत्र होगा।

  1. कुछ कस्टम विशेषता वर्ग बनाएं जो आपकी कक्षा की प्रत्येक सार्वजनिक संपत्ति के लिए कॉलम नाम रख सके।

  2. डेटाबेस से रिकॉर्ड पुनर्प्राप्त करने के बाद Product कक्षा और गणना गुणों की एक वस्तु को तुरंत चालू करें। प्रत्येक प्रॉपर्टी कस्टम विशेषता है कि के लिए - PropertyInfo की SetValue का उपयोग स्तंभ नाम कस्टम विशेषता में परिभाषित के अनुसार मान बदलने के लिए।

को ध्यान में समझें:

  • समाधान सरल कार्य करने के लिए काफी है और भूमि के ऊपर है, यह केवल समझ में आता है आप Product जैसे कई टेबल और कई वर्गों अगर - तो कुछ कैशिंग लंबे समय
में की आवश्यकता होगी - और स्वचालित रूप से उन सभी को प्रारंभ करने में एक कोड लिखना चाहते
  • प्रतिबिंब एक ओवरहेड ही है
  • +0

    यह दिलचस्प लगता है। मैं इसमें एक नज़र डालेगा। इसके अलावा, मैं अपने अवतार के रूप में * एल * के साथ एक लड़के से एक जवाब कैसे उठा सकता हूं !? :) – Polynomial

    +0

    धन्यवाद। :] कृपया यहां एलेक्स के एवर को देखें, क्योंकि मैंने यहां प्रस्तावित किए गए कोड के लिए कोड प्रदान किया है, इसलिए उसका जवाब बहुत बेहतर है * सिवाय इसके कि * मैं आपके 'उत्पाद' वर्ग 'फ़ील्ड पर कस्टम विशेषताओं का उपयोग करने की अत्यधिक अनुशंसा करता हूं। –

    +0

    हाँ, मैं अब इसमें देख रहा हूं। चीयर्स :) – Polynomial

    4

    आप एक ORM फ्रेमवर्क (इकाई की रूपरेखा आदि) का लाभ उठाने के लिए नहीं करना चाहते, तो आप इसे हाथ से कर सकते हैं:

    Product P = new Product(); // as per your example 
    using(SqlDataReader reader = ...) 
    { 
    while(reader.Read()) { P = MapToClass<Product(reader); /* then you use P */ } 
    } 
    
    :

    T MapToClass<T>(SqlDataReader reader) where T : class 
    { 
         T returnedObject = Activator.CreateInstance<T>(); 
         List<PropertyInfo> modelProperties = returnedObject.GetType().GetProperties().OrderBy(p => p.MetadataToken).ToList(); 
         for (int i = 0; i < modelProperties.Count; i++) 
          modelProperties[i].SetValue(returnedObject, Convert.ChangeType(reader.GetValue(i), modelProperties[i].PropertyType), null); 
         return returnedObject; 
    } 
    

    आप इस तरह इसका इस्तेमाल

    केवल ध्यान रखने योग्य चीज, क्वेरी में फ़ील्ड का क्रम है (इसे गुणों के क्रम से मेल खाना चाहिए क्योंकि उन्हें आपकी कक्षा में परिभाषित किया गया है)।

    आपको केवल कक्षा बनाने, एक प्रश्न लिखने की आवश्यकता है, फिर यह "मैपिंग" का ख्याल रखेगा।

    चेतावनी मैं इस पद्धति एक बहुत है और कभी नहीं किसी भी मुद्दे था उपयोग करें, लेकिन यह आंशिक वर्गों के लिए ठीक से काम नहीं करता है। यदि आप आंशिक मॉडल में आते हैं तो आप किसी भी ओआरएम फ्रेमवर्क का उपयोग करके बहुत बेहतर हैं।

    +0

    एलेक्स, यह गलत है। GetProperties() गारंटी नहीं देते हैं कि वापस लौटे PropertyInfo ऑब्जेक्ट्स घोषणा के क्रम में हैं। –

    +0

    मैं इस विधि का उपयोग करता हूं * बहुत * और वे हमेशा सही तरीके से चालू होते हैं ... ऑर्डर को लागू करना काफी आसान है, मैं कोड को अपडेट करने का मौका लेगा। – Alex

    +0

    मैं इसे भी कर;] लेकिन प्रलेखन इस पर स्पष्ट है: http://msdn.microsoft.com/en-us/library/aky14axb कैसे आप लागू करने के लिए यदि आप स्तंभ नाम-2- का कोई नक्शाकार है जा रहे हैं सम्पत्ति का नाम? –

    1

    एक संभावित समाधान:

    SQL क्वेरी में आप "PATH Mode with FOR XML " खंड का उपयोग कर सकते हैं।

    क्वेरी का परिणाम एक एक्सएमएल होगा, जिसे आप deserialize directly to C# objects कर सकते हैं।

    यह बड़े नेस्टेड एसक्यूएल प्रश्नों पर भी बहुत अच्छा काम करता है।

    -1
    select 'public ' + case DATA_TYPE 
    when 'varchar' then 'string' 
    when 'nvarchar' then 'string' 
    when 'DateTime' then 'DateTime' 
    when 'bigint' then 'long' 
    else DATA_TYPE end +' '+ COLUMN_NAME + ' {get; set;}' 
    from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='YOUR TABLE NAME' ORDER BY ORDINAL_POSITION 
    
    +0

    कृपया अधिक जानकारी के साथ संपादित करें। केवल कोड और "इसे आज़माएं" उत्तर निराश हैं, क्योंकि उनमें कोई खोज योग्य सामग्री नहीं है, और यह समझाएं कि किसी को "इसे आजमाएं" क्यों चाहिए। – abarisone

    +0

    यह सवाल का जवाब नहीं देता है। – Polynomial

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

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