Gibt es Fallstricke, wenn Sie einen iEnumerablen -Regretyps für SQL -Daten verwenden?

StackOverflow https://stackoverflow.com/questions/1400146

  •  05-07-2019
  •  | 
  •  

Frage

Meine Frage betrifft den SQL -Verbindungsstatus, das Laden usw. basierend auf dem folgenden Code:

public IEnumberable<MyType> GetMyTypeObjects()
{
  string cmdTxt = "select * from MyObjectTable";

  using(SqlConnection conn = new SqlConnection(connString))
  {
    using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
    {
      conn.Open();
      using(SqlDataReader reader = cmd.ExecuteReader())
      {
         while(reader.Read())
         {
            yield return Mapper.MapTo<MyType>(reader);
         }
       }
    }
  }
  yield break;
}

Ich kann sehen, dass dies möglicherweise ein Problem ist, wenn es viele Prozesse gibt, die mit langen Ausführungszeiten zwischen Iterationen des iEnumerablen Objekts ähneln, da die Verbindungen länger geöffnet sind Auf dem SQL -Server, da es nur Daten zurückgibt, wenn das iEnumerable -Objekt verwendet wird. Es senkt auch den Speicherverbrauch des Clients, da der Client nur eine Instanz von myType laden muss, während er funktioniert, anstatt alle Vorkommen von myType zu laden (indem er den gesamten DataReader durch Iterting durchführt und eine Liste oder etwas zurückgibt).

  • Gibt es irgendwelche Fälle, in denen Sie sich vorstellen können, wo Sie Ienumerable auf diese Weise nicht verwenden möchten, oder in Fällen, in denen Sie glauben, dass es perfekt passt?

  • Welche Art von Last stellt dies auf dem SQL -Server?

  • Ist dies etwas, das Sie in Ihrem eigenen Code verwenden würden (abgesehen von einer Erwähnung von Nhibernate, Subsonic usw.)?

  • -
War es hilfreich?

Lösung

Ich würde es nicht verwenden, weil es verbirgt, was passiert, und es könnte möglicherweise Datenbankverbindungen ohne ordnungsgemäße Entsorgung hinterlassen.

Das Verbindungsobjekt wird geschlossen, wenn Sie über den letzten Datensatz hinaus gelesen haben. Wenn Sie vorher nicht mehr lesen, wird das Verbindungsobjekt nicht entsorgt. Wenn Sie zum Beispiel wissen, dass Sie immer zehn Datensätze in einem Ergebnis haben und nur eine Schleife haben, in der diese zehn Datensätze vom Enumerator liest, ohne den elften Leseanruf zu tätigen, der über den letzten Artikel hinaus liest, ist die Verbindung nicht ordnungsgemäß geschlossen. Wenn Sie nur einen Teil des Ergebnisses verwenden möchten, können Sie die Verbindung nicht schließen, ohne den Rest der Datensätze zu lesen.

Sogar die eingebauten Erweiterungen für die Aufzähler können dies verursachen, auch wenn Sie sie richtig verwenden:

foreach (MyType item in GetMyTypeObjects().Take(10)) {
   ...
}

Andere Tipps

Dies ist kein Muster, dem ich folgen würde. Ich würde mich nicht so sehr um die Last auf dem Server kümmern wie um Sperren. Das Befolgen dieses Musters integriert den Datenabrufprozess in Ihren Geschäftslogikfluss, und das scheint ein Allround-Rezept für Schwierigkeiten zu sein. Sie haben keine Ahnung, was auf der Iterationsseite passiert, und Sie setzen sich in sie ein. Abrufen Sie Ihre Daten in einem Shot ab und lassen Sie den Client -Code dann aufzählen, sobald Sie den Leser geschlossen haben.

Ich empfehle gegen Voroptimierung. In vielen Situationen werden die Verbindungen zusammengefasst.

Ich erwarte auch keinen Unterschied in der Last auf SQL Server - die Abfrage wird bereits zusammengestellt und wird ausgeführt.

Meine Sorge wäre, dass Sie sich dem Kundencode vollständig ausgeliefert haben.

Sie haben bereits erwähnt, dass der aufrufende Code die Verbindung möglicherweise länger offen hält als streng erforderlich, aber es besteht auch die Möglichkeit, dass die Objekte niemals geschlossen/entsorgt werden können.

Solange der Clientcode verwendet foreach, using usw. oder ruft explizit den Aufzähler auf Dispose Methode dann geht es dir gut, aber es gibt nichts zu verhindern, dass es so etwas tut:

var e = GetMyTypeObjects().GetEnumerator();
e.MoveNext();    // open the connection etc

// forget about the enumerator and go away and do something else
// now the reader, command and connection won't be closed/disposed
// until the GC kicks in and calls their finalisers
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top