Autor Beitrag
Määx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 31.05.13 11:09 
Hallo zusammen,

ich würde gerne die Fehlerbehandlung meiner Datenbankabfragen in eine Funktionauslagern, damit ich dies nicht für jede Abfrage neu schreiben muss. Bisher mache ich dies wie folgt:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
try
{
  using(DBEntities db_context = new DBEntities ()){
    var result = (from pd in db_context.List_PD
                              where pd.ID == ID
                              select pd);
    foreach (List_PD entity_PD in result)
    {
      [...]
    }
  }
  success = true;
}
catch (Exception ex)
{
  System.Diagnostics.Debug.WriteLine("Error SQL-Entity: " + ex.Message);
  success = false;
}


jetzt würde ich das ganze gerne in eine Funktion kapseln:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
string sqlQuery = (from pd in db_context.List_PD
                              where pd.ID == ID
                              select pd).ToString();
executeSQL(sqlQuery, "loading PD");

private var executeSQL(string sqlQuery, string errorMsg){
  var result = null;
  try
  {
    using(DBEntities db_context = new DBEntities ()){
      result = sqlQuery //???
      return result;
    }
  }
  catch (Exception ex)
  {
    System.Diagnostics.Debug.WriteLine("Error SQL-Entity "+errorMsg+": " + ex.Message);
    return null
  }
}

Nur leider kann ich keine Funktion vom Rückgabewert var definieren und weiss auch nich wie ich die Abfrage vernünftig üergeben kann. Hatte auch schon überlegt die executeSQL generisch zu erstellen und die Entität mit zu übergeben. Hat aber auch irgendwie nicht funktioniert. Welchen Ansatz würdet ihr wählen? Oder gibt es vll. sogar schon solche Methode direkt im EntityFramework?

Vielen Dank
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 31.05.13 12:52 
Hallo Määx,

kennst du dich schon mit Delegates und anonymen Methoden sowie Lambda-Ausdrücken aus?

Zuersteinmal ist bei deinem Code der Datentyp string (für die SqlQuery) falsch - ein Linq-Ausdruck ist vom Typ IQueryable (bzw. IQueryable<T>).

Ich gebe dir jetzt zwar mal die Lösung, aber lese dich ersteinmal in die oben genannten Begriffe ein (um den Code auch wirklich zu verstehen):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
using System;
using System.Linq; // evtl. noch weitere using-Direktiven

var query = executeSQL(
    db_context => from pd in db_context.List_PD
                  where pd.ID == ID
                  select pd,
    "loading PD");

private IQueryable executeSQL(Func<DBEntities, IQueryable> sqlQuery, string errorMsg)
{
    var result = null;
    try
    {
        using(DBEntities db_context = new DBEntities())
        {
            result = sqlQuery(db_context);
            return result;
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Error SQL-Entity " + errorMsg + ": " + ex.Message);
        return null;
    }
}


Alternativ auch als IQueryable<T>:
ausblenden C#-Quelltext
1:
private IQueryable<T> executeSQL<T>(Func<DBEntities, IQueryable<T>> sqlQuery, string errorMsg)					

Dann mußt du den Datentyp der Tabelle jeweils beim Aufruf als generischen Parameter angeben.

Für diesen Beitrag haben gedankt: Määx
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 31.05.13 14:12 
ok, denke ich habe das so weit verstanden und es funktioniert nach kleiner Änderung bei mir auch. Ich übergebe der Funktion quasi als Lambda-Ausdruck eine neue Funktion, die mir die entsprechenden resultate liefern soll. Was ich jedoch ändern musste war das
ausblenden C#-Quelltext
1:
using(DBEntities db_context = new DBEntities())					

Hierdurch wir der Context ja direkt nach dem Aufruf wieder freigegeben und steht dann zum Bearbeiten des zurückgegebenen Ergebnisses nicht mehr zur Verfügung. Ich habe diesen nun als dbContext global definiert und mit null initialisiert. Dies prüfe ich dann in der executeSQL und erzeuge den dbContext ggf neu.

Eidt: Ok, wie ich feststellen musste ist das EntityFramework nicht ThreadSave. Also ist eine globale erzeugung des Context -in meinem Fall- nicht sinnvoll! Entsprechend übergebe ich diesen nun immer mit an die Funktion!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 01.06.13 10:10 
Hallo,

ja, das hatte ich nicht bedacht (obwohl ich selbiges Problem bei meinem aktuellen Projekt habe).
Aufgrund des Connection-Poolings sollte man die Entitäten immer nur kurzzeitig benutzen.

Eine Alternative dazu wäre, daß die Methode schon die "materialisierten" Werte zurückgibt, also als List<T>:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
private IList<T> executeSQL<T>(Func<DBEntities, IQueryable<T>> sqlQuery, string errorMsg)
{
   // ...
   return result.ToList();
}

Möchte man hingegen den Rückgabewert für weitere Linq-Funktionalitäten (direkt auf der Datenbank) benutzen, so muß man wohl (wie du in deinem Edit beschrieben hast) den Context von außen erzeugen und übergeben.
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: So 02.06.13 10:37 
Hey,

das mit der Rückgabe als List<t> ist eine sehr gute Idee und ich werde das entsprechend noch ändern! Bei der obigen Lösung kommt nämlich hinzu, dass man dadurch, dass man ja immer noch direkt auf der DB arbeitet und somit bei z.B. bei fehlender Verbindung Fehler erzeugt werden. Das ist bei mir zumindestens passiert: "Fehler beim zugrunde liegenden Anbieter auf Open."

Also muss man trotzdem jede weitere Bearbeitung in ein try/catch legen. Benötigt man also keine weiteren Linq-Funktionalitäten ist Th69 Lösung wohl die beste!
Vielen Dank!