2009-07-12 18 views
2

J'ai été affecté à un projet où le DAL est constitué d'une classe de base avec des fonctions pour renvoyer IDataReader, un objet (int, string et autres) ou un DataSet. Une fonction ExecuteNonQuery existe également. Ce DAL accède uniquement aux USP (SQL Server) et utilise SqlHelper de MS pour exécuter les requêtes. Voici deux exemples de fonctions de la base:Élimination de SqlConnection d'une classe DAL de base lors de l'appel de ExecuteReader

protected IDataReader ExecuteReader(string storedProcedure, params object[] parameterValues) 
    { 
     SqlConnection HConnection = new SqlConnection(myConnString); 
     IDataReader ret = null; 
     try 
     { 
      ret = SqlHelper.ExecuteReader(HConnection, storedProcedure, parameterValues); 
     } 
     catch (Exception ex) 
     { 
      HanldeError(ex, storedProcedure, parameterValues); 
     } 
     return ret; 
    } 

    protected object ExecuteScalar(string storedProcedure, params object[] parameterValues) 
    { 
     using (SqlConnection HConnection = new SqlConnection(myConnString)) 
     { 
      object ret = null; 
      try 
      { 
       ret = SqlHelper.ExecuteScalar(HConnection, storedProcedure, parameterValues); 
      } 
      catch (Exception ex) 
      { 
       HanldeError(ex, storedProcedure, parameterValues); 
      } 
      return ret; 
     } 
    } 

D'autres classes dérivent de cette classe de base, la création de classes DAL spécifiques à la tâche, par exemple:

public class Orders : BaseDal { 
    public IDataReader GetOrdersList(int clientId, int agentId) 
    { 
     return ExecuteReader("usp_Orders_GetOrdersList", clientId, agentId); 
    } 
    ... 
} 

Ensuite, il y a des classes BLL qui appellent les fonctions DAL et remplir des objets (par exemple un objet de commande) avec les données sur la base des données lues à partir de l'objet IDataReader:

public Order[] GetOrdersList(int ClientIDX, int AgentIDX) 
    { 
     List<Order> ret = null; 
     using (IDataReader dr = objDAL.GetOrdersList(ClientIDX, AgentIDX)) 
     { 
      if (dr != null) 
      { 
       ret = new List<Order>(); 
       while (dr.Read()) 
       { 
        ret.Add(xReadOrder(dr, 0)); 
       } 
      } 
     } 
     return ret.ToArray(); 
    } 

Ma question est - si vous regardez le code pris à partir de BaseDal, vous remarquerez que seul ExecuteScalar termine réellement l'objet SqlConnection (l'instruction using) - c'est le cas avec toutes mes fonctions ici. Avec ExecuteReader je ne peux pas faire cela, car je retourne un objet SqlDataReader ouvert et la fermeture de la connexion invalidera le lecteur. Tout le code qui obtient et utilise un IDataReader de la DAL utilise l'instruction using, mais l'objet SqlConnection est également éliminé, ou est-il GCé à un stade ultérieur, blessant le pool de connexions en ne le libérant pas? plus tôt? Si oui, comment cela peut-il être traité?

De même, existe-t-il une meilleure approche pour créer une couche d'accès logique que celle décrite ci-dessus? Je suis moins préoccupé par DAL agnostique magasin de données, nous avons seulement besoin d'un solide et facile à maintenir un, un qui peut prendre de nombreuses connexions simultanées à partir de nombreux threads.

Merci d'avance pour toute aide à ce sujet.

Répondre

4

SqlDataReader fermera la connexion si vous spécifiez CommandBehavior.CloseConnection lorsque vous exécutez la commande. Cependant, il se sent un peu moche de toute façon.

Au lieu de cela, passez un SqlConnectionen la méthode et l'utiliser. Ensuite, l'appelant a le contrôle sur quand cela est disposé. Vous pouvez également exécuter un Action<SqlDataReader> pour exécuter le lecteur ouvert et faire en sorte que la méthode ferme à la fois le lecteur et la connexion, après l'exécution de l'action. Cette action devrait alors faire tout ce dont elle avait besoin avec le lecteur, bien sûr.

+0

Merci. Bien que vous considériez cela comme «moche», utiliser 'CommandBehavior.CloseConnection' semble être ma meilleure option, car c'est ce que fait SqlHelper en interne lorsqu'il transmet une chaîne de connexion (par opposition à un objet' SqlConnection'). Passer 'SqlConnection' dans la méthode n'est pas une option, car cela va contredire la séparation DAL/BLL que j'essaie de garder. L'approche 'Action ' que je ne connais pas, mais cela semble un peu difficile à faire. Juste pour être sûr - pouvez-vous me désigner à un bon endroit pour voir ce que cela signifie exactement? – synhershko

+0

Euh, pas facilement (je suis en train d'essayer de réparer quelque chose) - mais vous utiliseriez une expression lambda pour dire "quand vous avez le lecteur ouvert, c'est ce que je veux faire avec" en gros . –