First of all, I'm a Java programmer, and I'm new to C #, and I need the opinions of C # developers. I am developing an application that connects to a database (firebird 1.5), requests some data and returns to me, so there is nothing complicated, but, unfortunately, I am stuck in some things:
As you know, the connection to the database must be performed in a separate thread, because this is a high-weight operation, and all connections must be in the connection pool in order to reuse an already open connection, create a new one instead.
So, here is my first question - how to organize a connection pool? (As for the connection pool that I read, as a rule, the connection pool is already implemented by the data providers, and I can just set it in the connection parameters, for example, "connectionBuilder.Pooling = true;")
What about queries? I mean, I always use Query per-Thread (and I think it’s right, we also do a high-weight operation, am I wrong? In any case, I would be glad to see your best practices with organizing work with databases data ), and in Java, I simply return the result of the request from a separate thread using interfaces and anonymous classes as follows:
In DBHelper.class (DBHelper - single line)
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 code ..... listener.onSucces(myPromoActions); } catch(Exception e) { listener.onError(e); } finally { closeDatabase(); } } }
in some UI class (for 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(); }
In C #, I have to use delegates to indicate which method will be executed on the thread, but unfortunately I cannot send any callback as a parameter - so how should I return the results of the request to the main user interface thread ?
UPD
I am a little versed in how to work with delegates and events, but there is a problem with creating a custom event. I declared an EventHandler and a custom EventArgs:
public delegate void QueryResultEventHandler(object sender, QueryResultEventArgs e); public class QueryResultEventArgs : EventArgs { public List<String> QueryResult { get; set; } public int QueryRecordsCount { get; set; } }
And in My DBHelper.class, I declared the following field and event:
private QueryResultEventHandler _queryResult; public event QueryResultEventHandler onQueryResult { add { lock (this) { _queryResult += value; } } remove { lock (this) { _queryResult -= value; } } }
In the user interface class (MainWindow), I use the following code:
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 }
So my problem is how to raise an event asynchronously? In my DBHelper.class, I am trying to use beginInvoke & endInvoke with the _query delegate, but it seems like I have missed some lines of code, whatever that is. I cannot understand what I am doing wrong, as for an asynchronous event ? Here is my DBHelper.class code:
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); } }