Po pierwsze, jestem programistą Java i jestem nowy na C# i potrzebuję opinii programistów C#. Zajmuję się tworzeniem aplikacji, która łączy się z bazą danych (firebird 1.5), wysyła zapytanie do niektórych danych i wraca do mnie, więc nic nie musi być skomplikowane, ale niestety utknąłem w kilku rzeczach:Najlepsze praktyki: C# praca z DB
Jak wiemy, połączenie z bazą danych powinno być realizowane w oddzielnym wątku, ponieważ jest to operacja o dużej masie i wszystkie połączenia powinny znajdować się w puli połączeń, aby ponownie użyć już otwartego połączenia, a zamiast tego utworzyć nowe.
Oto moje pierwsze pytanie - jak poprawnie zorganizować basen? (co z puli połączeń Czytałem, że zwykle basen połączenie jest już realizowany przez dostawców danych i można po prostu ustawić go w parametrach połączenia jakoś jak „connectionBuilder.Pooling = true;”)
Co o zapytaniach? Chodzi mi o to, że zawsze używam kwerendy na wątek (i myślę, że to jest w porządku, ponieważ wykonujemy również operację z dużą masą, czy nie myliłem się? W każdym razie, chciałbym zobaczyć twoje najlepsze praktyki z organizowaniem pracy z bazami danych) i Java po prostu robię wyniku kwerendy powrócić z osobnym wątku przez użyć interfejsy i klas anonimowych tak:
w DBHelper.class (DBHelper jest pojedyncza)
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();
}
}
}
w niektórych Klasa UI (dla 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();
}
W języku C# należy użyć delegatów z okazji, która metoda będzie wykonywał w wątku, ale unfortionally nie mogę wysłać żadnego zwrotnego jako parametr - tak jak mam wrócić mojej kwerendy wyniki do głównego wątku UI?
UPD
mam rozumieć trochę jak pracować z delegatów i zdarzeń, ale mają problemy z podnoszeniem zdarzenia niestandardowego. Miałem ogłoszony eventhandler i niestandardowych EventArgs:
public delegate void QueryResultEventHandler(object sender, QueryResultEventArgs e);
public class QueryResultEventArgs : EventArgs
{
public List<String> QueryResult { get; set; }
public int QueryRecordsCount { get; set; }
}
i moim DBHelper.class oświadczyłem kolejne pole i zdarzenie:
private QueryResultEventHandler _queryResult;
public event QueryResultEventHandler onQueryResult
{
add
{
lock (this)
{
_queryResult += value;
}
}
remove
{
lock (this)
{
_queryResult -= value;
}
}
}
W klasy UI (MainWindow) używam następny kod:
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
}
Więc moim problemem jest teraz jak asynchronicznie podnieść wydarzenie? W moim DBHelper.class Próbuję użyć beginInvoke & endInvoke z delegacja _query, ale wydaje się, że brakowało niektórych linii kodu, co to było, nie mogę zrozumieć, co robię źle, jak podnieść zdarzenia asynchronicznie? Tutaj mój DBHelper .Klasa Kod:
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);
}
}
Łączenie połączeń z bazy danych będzie bardzo korzystne, jeśli pozwoli na to architektura. Jeśli tworzysz aplikację typu serwer klienta, tj. Front, który łączy się bezpośrednio z serwerem, to brak jest takiego połączenia w puli połączeń. Czy łączysz się z bazą danych bezpośrednio z aplikacji klienckiej. – Namphibian
@Namphibian Tak, rozwijam aplikację typu klient-serwer i łączę się bezpośrednio z bazą danych. – whizzzkey
W twoim przypadku dodanie puli połączeń to tylko zwiększenie złożoności i brak korzyści. Zazwyczaj pula połączeń znajduje się na serwerze aplikacji. Aby czerpać korzyści z łączenia połączeń, musisz przejść do architektury n-warstwowej. – Namphibian