2015-04-06 4 views
8

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

जैसा कि हम जानते हैं कि डेटाबेस कनेक्शन होना चाहिए अलग थ्रेड में एहसास हुआ क्योंकि यह एक उच्च वजन वाला ऑपरेशन है और सभी कनेक्शन पहले से ही खोले गए कनेक्शन का पुन: उपयोग करने के लिए कनेक्शन पूल में होना चाहिए, बल्कि नया बनाएं।

तो मेरा पहला प्रश्न - कनेक्शन पूल को व्यवस्थित तरीके से व्यवस्थित करने के लिए यहां जाएं? (क्या कनेक्शन पूल के बारे में मैं पढ़ा है कि आम तौर पर कनेक्शन पूल पहले से ही डेटा प्रदाताओं ने महसूस किया है और मैं बस किसी न किसी प्रकार कनेक्शन parametres में सेट कर सकते हैं "connectionBuilder.Pooling सच =," की तरह)

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

DBHelper.class में

public interface QueryListener { 

    public void onSuccess(ArrayList<?>); 

    public void onError(Exception e); 
} 

public synchronized void getPromoActions(final QueryListener listener) { 
    if (listener != null) { 
     try { 
     ArrayList<String> myPromoActions; 
     ............. 
     // some query's code 
     ..... 
     listener.onSucces(myPromoActions); 
     } catch(Exception e) { 
     listener.onError(e); 
     } finally { 
     closeDatabase(); 
     } 
    } 
} 
कुछ में

(DBHelper एक सिंगलटन है) यूआई-श्रेणी (eaxample MainWindow के लिए)

public void getPromoActions(){ 
    new Thread(new Runnable() { 
    @Override 
    public void run() { 
     DBHelper.getInstance().getPromoActions(new QueryListener() { 

     @Override 
     public void onSuccess(ArrayList<?>) { 
      // set Data to UI element such as Table 
     } 

     @Override 
     public void onError(Exception e){ 
      // Handling exception 
     } 
     }); 
    } 
    }).start(); 
} 

सी # में मैं चिह्नित करने के लिए कौन सी विधि सूत्र में निष्पादित करेंगे प्रतिनिधियों का उपयोग करना चाहिए, लेकिन unfortionally मैं पैरामीटर के रूप में किसी भी कॉलबैक नहीं भेज सकते हैं - तो कैसे मैं अपने क्वेरी लौटना चाहिए मुख्य यूआई थ्रेड के परिणाम?

युपीडी

मैं थोड़ा कैसे प्रतिनिधियों और घटनाओं के साथ काम करने के लिए समझ में है, लेकिन एक कस्टम घटना को ऊपर उठाने के साथ एक समस्या है।

private QueryResultEventHandler _queryResult; 

public event QueryResultEventHandler onQueryResult 
{ 
    add 
    { 
    lock (this) 
    { 
     _queryResult += value; 
    } 
    } 

    remove 
    { 
    lock (this) 
    { 
     _queryResult -= value; 
    } 
    } 
} 

में यूआई वर्ग (MainWindow) मैं का उपयोग करें:

public delegate void QueryResultEventHandler(object sender, QueryResultEventArgs e); 

public class QueryResultEventArgs : EventArgs 
{ 
    public List<String> QueryResult { get; set; } 
    public int QueryRecordsCount { get; set; } 
} 

और मेरे DBHelper.class में मैं एक अगले क्षेत्र और घटना की घोषणा की: मैं एक eventhandler और एक कस्टम EventArgs की घोषणा की थी अगला कोड:

public void GetAllDistricts() { 
     DBHelper.Instance.onQueryResult += new QueryResultEventHandler(GetAllDistricsResultHandler); 
     DBHelper.Instance.GetAllDistricts(); 
    } 

public void GetAllDistricsResultHandler(object sender, QueryResultEventArgs e){ 
     // Here I'm adding the query result to Table 
    } 

तो मेरी समस्या अब एक घटना को असंकालिक रूप से कैसे विकसित करना है? मेरे DBHelper.class मैं startInvoke & _query प्रतिनिधि के साथ endInvoke का उपयोग करने की कोशिश कर रहा हूं, लेकिन ऐसा लगता है कि मुझे कुछ कोड लाइनों को याद आया था जो मैं समझ नहीं पाया था कि मैं क्या कर रहा हूं कि घटना को कैसे बढ़ाया जाए असीमित रूप से? यहां मेरा डीबीहेल्पर।वर्ग कोड:

public void GetAllDistricts() { 
    try 
    { 
     if (_queryResult != null) 
     { 
     //** This code should run asynchronously ----------> 

     using (FbConnection connection = GetConnection()) 
     { 
      FbCommand getAllDistrictsCommand = new FbCommand(); 

      getAllDistrictsCommand.CommandText = "SELECT * FROM SEND"; 
      getAllDistrictsCommand.Connection = connection; 

      QueryResultEventArgs args = new QueryResultEventArgs(); 
      using (FbDataReader reader = getAllDistrictsCommand.ExecuteReader()) 
      { 
      while (reader.Read()) 
      { 
      //Here must be the processing of query results and filling the 
      //QueryResultEventArgs 
       args.QueryResult.Add(reader[0].ToString()); 
      }      
      args.QueryRecordsCount = reader.GetInt32(reader.GetOrdinal("Rows")); 

      // And here after sucessfull query I should call OnQueryResult() 
      OnQueryResult(args); 
      } 
     } 
     //**<-------------------- 
     } 
     else 
     { 
     throw new Exception("...Some exception message..."); 
     } 
    } 
    catch (Exception e) 
    { 
    log.ErrorException(e.Message, e); 
    throw new Exception("...Some exception message...");; 
    } 
    finally { 
    CloseConnection(); 
    } 
} 

// The QueryResultEvent method 
protected void OnQueryResult(QueryResultEventArgs e) 
{ 
    if (_queryResult != null) 
    { 
    _queryResult(this, e); 
    } 
} 
+0

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

+0

@Namphibian हां, मैं क्लाइंट-सर्वर प्रकार का अनुप्रयोग विकसित कर रहा हूं और सीधे डेटाबेस से कनेक्ट कर रहा हूं। – whizzzkey

+1

आपके मामले में एक कनेक्शन पूल जोड़ने में जटिलता और कोई लाभ नहीं जोड़ रहा है। आम तौर पर एक कनेक्शन पूल एक आवेदन सर्वर पर होगा। कनेक्शन पूलिंग के लाभों का लाभ उठाने के लिए आपको एन-स्तरीय आर्किटेक्चर में स्थानांतरित करने की आवश्यकता होगी। – Namphibian

उत्तर

8

कनेक्शन पूलिंग के बारे में पहले। यदि आप ADO.NET का उपयोग करेंगे तो आपको इसके बारे में चिंता करने की आवश्यकता नहीं है, क्योंकि यह पहले से ही है। आप आप सिर्फ एक कनेक्शन बनाने के बिना कोई अतिरिक्त कार्य की जरूरत नहीं है,:

using (var connection = new SqlConnection(connectionString)) 
{ 
    // Queries to DB 
} 

आप चाहिए हमेशा बंद या निपटान आप कनेक्शन। विधियों के नाम "डरावना" लगते हैं लेकिन वास्तव में कनेक्शन का पुन: उपयोग किया जाता है। अधिक जानकारी प्राप्त करने के लिए कृपया MSDN article पढ़ें।

आपके द्वारा प्रस्तावित कोड अधिक जटिल दिखता है। मुझे लगता है कि आपको async/await पैटर्न का उपयोग करने पर विचार करना चाहिए जो सामान्य रूप से बहुप्रचारित नहीं है, लेकिन यह यूआई प्रतिक्रियात्मकता मुद्दों को संभालता है और कोड लिखने/पढ़ने को सरल बनाता है। .NET के नए संस्करणों में लगभग सभी विधियों को निष्पादित करने में संभावित रूप से लंबे समय तक एसिंक संस्करण हैं। उदाहरण के लिए आपके डेटा का उपयोग परत है कि कैसा लग सकता है (मैं Dapper ORM'sQueryAsync विधि का उपयोग कर रहा हूँ बस कोड संक्षिप्त और सरल रखने के लिए): कहीं

public async Task<IList<District>> GetAllDistrictsAsync() 
{ 
    using (var connection = await GetConnectionAsync()) 
    { 
     return (await connection.QueryAsync<District>("select * from Districts")).ToList(); 
    } 
} 

public async Task<IDbConnection> GetConnectionAsync() 
{ 
    var connectionString = 
     ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString; 
    var connection = new SqlConnection(connectionString); 
    await connection.OpenAsync(); 
    return connection; 
} 

और फिर यूआई पर:

private async void Button_Click(object sender, EventArgs e) 
{ 
    var districts = await GetAllDistrictsAsync(); 
} 

आप तो अभी भी Tasks नेमस्पेस को देखने के लिए आपको विभिन्न थ्रेड में कुछ कोड निष्पादित करने की आवश्यकता है।

Task.Factory 
    .StartNew<IList<District>>(GetAllDistricts) 
    .ContinueWith(districts => 
    { 
     // UI thread 
    }, TaskScheduler.FromCurrentSynchronizationContext()); 

इस उदाहरण GetAllDistricts में async नहीं है और अलग अलग सूत्र में निष्पादित किया जाता है। लेकिन को यूआई थ्रेड में TaskScheduler.FromCurrentSynchronizationContext() के कारण निष्पादित किया जाएगा।

+0

यदि आपके कोई अतिरिक्त प्रश्न हैं, तो मैं उन्हें भी उत्तर जोड़ सकता हूं (यदि मैं निश्चित रूप से कर सकता हूं)। Pozhalujsta;) –

+0

कृपया बहुत दयालु हो ** druzhishe =) **, मुझे अगली बात समझाओ - क्या यह असीमित संचालन के लिए प्रतिनिधियों और घटनाओं का उपयोग करने का एक बुरा अभ्यास है? और यदि यह है, तो मुझे दिलचस्पी है क्यों? सादर। – whizzzkey

+1

यह करने का पुराना तरीका है, async इसे आसान बनाने के लिए एक नई सुविधा है। एसिंक आपको घटना को संसाधित करने के लिए तर्क को रखकर सबसे अच्छी पठनीयता प्राप्त करने देता है और फ्रेमवर्क को उस तथ्य को संभालने की इजाजत देता है जिसे आप यूआई थ्रेड को अवरुद्ध नहीं करना चाहते हैं, लेकिन उस थ्रेड में अपनी प्रसंस्करण जारी रखना चाहते हैं। यदि आप इसे घटनाओं के साथ असीमित रूप से करना चाहते हैं तो आपको खुद को थ्रेडिंग को संभालना होगा (यूआई थ्रेड पर वापस नियंत्रण प्राप्त करना शामिल है क्योंकि आपका यूआई थ्रेड-सुरक्षित होने की संभावना नहीं है - यह कैसे करें इसके लिए आप जो भी उपयोग कर रहे हैं उसके आधार पर भिन्न होता है यूआई, यदि आप WPF में हैं तो यह डिस्पैचर के माध्यम से है)। – fyjham

1
public void GetAllDistricts() { 

     DBHelper.Instance.onQueryResult += 
        new QueryResultEventHandler(GetAllDistricsResultHandler); 

     new Thread(
      new ThreadStart(DBHelper.Instance.GetAllDistricts) 
      ).Start(); 

    } 

लेकिन समस्या यह है कि आप का सामना करना पड़ेगा कि आप eventhandler से अपने यूआई नियंत्रणों को एक्सेस करने में सक्षम नहीं होगा के रूप में यह मना कर दिया जाएगा क्योंकि आप एक ही धागे में अब और नहीं कर रहे हैं ...

How to update the GUI from another thread in C#?

से बचने के लिए इस आप शायद BackgroundWorke उपयोग कर सकते हैं कुछ स्पष्टीकरण के लिए है कि लेख का संदर्भ लें आर नियंत्रण।

+0

का उपयोग अपनी प्रतिक्रिया के लिए बहुत बढ़िया धन्यवाद। – whizzzkey

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