2017-10-02 3 views
0

Ich gehe über einen längeren Datenzugriffscode einer etwas älteren App. Jede Funktion ruft eine gespeicherte Prozedur auf, um etwas aus Oracle DB auszuwählen. Jede Funktion mehr oder weniger sieht aus wie dem folgenden Code:Welche Best Practices arbeiten mit Oracle.DataAccess.Client?

public List<SomeObject> GetMeSomethingFromDB(string myParam, int anotherParam) 
{ 
    OracleConnection conn = null; 
    OracleDataReader dataReader = null; 
    try 
    { 
     conn = new OracleConnection(Settings.ConnectionString); 
     conn.Open(); 

     var cmd = new OracleCommand("STORED_PROC_NAME", conn); 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add(new OracleParameter("IN_MY_PARAM", OracleDbType.Varchar2)).Value = myParam; 
     cmd.Parameters.Add(new OracleParameter("IN_ANOTHER_PARAM", OracleDbType.Int32)).Value = anotherParam; 
     cmd.Parameters.Add(new OracleParameter("OUT_REF_CURSOR", OracleDbType.RefCursor)).Direction = ParameterDirection.Output; 
     dataReader = cmd.ExecuteReader(); 

     List<SomeObject> result = new List<SomeObject>(); 
     if (dataReader == null || !dataReader.HasRows) return result; 

     while (dataReader.Read()) 
     { 
      SomeObject someObject = new SomeObject 
      { 
       SomeId = (int)dataReader["SOME_ID"], 
       SomeStringValue = dataReader["SOME_STRING_VALUE"].ToString() 
      }; 

      result.Add(someObject); 
     } 

     return result; 
    } 
    catch (Exception e) 
    { 
     throw e; 
    } 
    finally 
    { 
     if (dataReader != null) 
     { 
      dataReader.Close(); 
      dataReader.Dispose(); 
     } 
     if (conn != null) 
     { 
      if (conn.State == ConnectionState.Open) conn.Close(); 
      conn.Dispose(); 
     } 
    } 
} 

Meine Fragen sind:

  1. Einige Funktionen statt Klassenstufe OracleConnection Variable verwenden. Was ist bevorzugt - Funktionsebene oder Klassenebene variabel?
  2. Ist die Prüfung dataReader == null erforderlich? Wäre es jemals NULL nach cmd.ExecuteReader() Anruf?
  3. Die Funktionen unterscheiden sich, wenn es um die Verbindung Schließen/Dispose und Leser Close/Dispose geht. Was ist der richtige Weg um zu schließen? Würde der Leser nicht automatisch geschlossen/entsorgen, wenn die Verbindung entsorgt wird?
  4. Ich suche Oracle.ManagedDataAccess.Client zu diesem Projekt in naher Zukunft zu verbinden. Wird irgendetwas in diesem Code geändert, um mit dem Client für verwalteten Datenzugriff zu arbeiten?
  5. Alles andere, Best Practices/Vorschläge sind willkommen.

Vielen Dank.

+2

Wenn Sie eine gefangene Ausnahme erneut auslösen, tun Sie nicht 'throw e;'. Tun Sie einfach 'throw;', damit Sie Ihre Stack-Trace beibehalten. – mason

+0

@ Mason - danke – Dimskiy

Antwort

3

Die using statement wird viel Ihren Code vereinfachen.

public List<SomeObject> GetMeSomethingFromDB(string myParam, int anotherParam) 
{ 
    using (OracleConnection conn = new OracleConnection(Settings.ConnectionString)) 
    using (OracleCommand cmd = new OracleCommand("STORED_PROC_NAME", conn)) 
    { 
     conn.Open(); 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add(new OracleParameter("IN_MY_PARAM", OracleDbType.Varchar2)).Value = myParam; 
     cmd.Parameters.Add(new OracleParameter("IN_ANOTHER_PARAM", OracleDbType.Int32)).Value = anotherParam; 
     cmd.Parameters.Add(new OracleParameter("OUT_REF_CURSOR", OracleDbType.RefCursor)).Direction = ParameterDirection.Output; 
     using (OracleDataReader dataReader = cmd.ExecuteReader()) 
     { 
      while (dataReader.Read()) 
      { 
       SomeObject someObject = new SomeObject 
       { 
        SomeId = (int)dataReader["SOME_ID"], 
        SomeStringValue = dataReader["SOME_STRING_VALUE"].ToString() 
       }; 
       result.Add(someObject); 
      } 
     } 
    } 
    return result; 
} 
  1. Verwenden Sie immer ein lokales Verbindungsobjekt und es in einem mit Anweisung, um eine korrekte Schließen und Entsorgung des Objekts haben (das gleiche auch für die OracleDataReader und OracleCommand gilt). Dieser Ihren Server aus dem Speicher frei wird und Threads die Verbindung mit dem Code und Leistungen garantiert von ADO.NET-Provider
  2. No aktiviert durch die connection pooling sind erforderlich zu halten, wird der Anruf nicht notwendig, und weder der Aufruf an HasRows wenn Sie planen, über das Ergebnis zu schleifen. Der Leser gibt false zurück, wenn keine Zeilen vorhanden sind oder wenn Sie das Ende des Datensatzes erreichen
  3. Siehe den Punkt über die using-Anweisung. Korrekte Verwendung von Anweisungen wird dieses Problem von Ihren Lasten entfernen.
  4. Sie should't mit diesem Code irgendein Problem haben, wenn Sie den ODP Anbieter von Oracle verwenden
  5. Es gibt keine Notwendigkeit, einen Versuch fangen haben, wenn Sie nur die Ausnahme erneut auslösen möchten. Lassen Sie es einfach auf die obere Ebene sprudeln, ohne den Stack-Trace mit einer throw e zu unterbrechen, und der gesamte Code, der in der finally-Anweisung benötigt wird, wird vom Compiler implizit hinzugefügt, indem die geschweifte Klammer verwendet wird.
+0

Ich habe mehr Erfahrung mit SQL-Server, wo in der Tat verwende ich immer mit Anweisungen. Was mich davon abhält, ist, dass weder OracleConnection noch OracleCommand IDisposable implementieren. Würden Aussagen immer noch ihre Aufgabe erledigen? Namespace Oracle.DataAccess.Client { öffentliche versiegelte Klasse OracleConnection: DbConnection, ICloneable – Dimskiy

+0

@Dimskiy Ja implementieren sie IDisposable. Vielleicht nicht direkt, sondern durch Erben von einer Klasse, die das tut. – mason

+0

@ Mason - Du hast absolut recht! Vielen Dank. Öffentliche abstrakte Klasse DbConnection: Komponente, IDbConnection, IDisposable – Dimskiy