2010-11-05 4 views
1

Bonjour, J'ai créé ma première méthode générique reconstituée à partir d'un tas de recherches Google. J'aimerais que quelqu'un me regarde et me dise si je ne respecte pas les règles importantes ou s'il y a des façons d'améliorer cette méthode.Méthode générique. Assigner des propriétés d'un DataReader à des objets génériques

La méthode appelle une procédure stockée dans sql, puis utilise la réflexion pour affecter les propriétés en fonction des valeurs lues dans le schéma DataReader. Les procédures stockées sont codées de sorte qu'elles renvoient les noms de propriété exacts attendus par les classes. Voici le code:

 public static List<T> GetList<T>(string SQLServer, string DBName, 
     string ProcedureName, Dictionary<string, string> Parameters) 
     where T : new() 
    { 
     List<T> list = new List<T>(); 

     //Setup connection to SQL 
     SqlConnection SqlConn = new SqlConnection(ConnectionString(SQLServer, DBName)); 
     SqlCommand SqlCmd = new SqlCommand(ProcedureName, SqlConn); 
     SqlCmd.CommandType = System.Data.CommandType.StoredProcedure; 
     SqlDataReader reader; 

     //Process Parameters if there are any 
     foreach (KeyValuePair<string, string> param in Parameters) 
     { 
      SqlCmd.Parameters.AddWithValue(param.Key, param.Value); 
     } 

     SqlConn.Open(); 
     reader = SqlCmd.ExecuteReader(); 

     //Get The Schema from the Reader 
     //The stored procedure has code to return 
     //the exact names expected by the properties of T 
     DataTable schemaTable = reader.GetSchemaTable(); 
     List<string> fields = new List<string>(); 
     foreach (DataRow r in schemaTable.Rows) 
     { 
      fields.Add(r[0].ToString()); 
     } 


     while (reader.Read()) 
     { 
      T record = new T(); 

      foreach (string field in fields) 
      { 
       //Assign the properties using reflection 
       record.GetType().GetProperty(field).SetValue(
        record, reader[field], 
        System.Reflection.BindingFlags.Default, 
        null,null,null); 
      } 

      list.Add(record); 
     } 
     return list; 
    } 
+1

Avez-vous considéré Linq To SQL? http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx – xcud

+1

Les actions Db ont un coût. Ajoutez du reflet à ça, ça va être sensiblement plus lent. Pire, vous le faites dans la boucle. Vous devriez déplacer la partie de réflexion en dehors de la boucle, et de préférence compter sur les arbres d'expression au lieu de la réflexion. Voir cette réponse http://stackoverflow.com/a/19845980/661933 pour, par exemple, – nawfal

+0

Connexe: http://stackoverflow.com/questions/812034/fastest-way-to-use-reflection-for-converting-datareader-to-list, http://stackoverflow.com/questions/1105549/c-sharp -idatareader-to-object-mapping-using-generics – nawfal

Répondre

1

Je ne sais pas si c'est quelque chose que je ferais ou non. J'utiliserais probablement un ORM en premier, par ex. Cadre d'entité. Je l'ai fait des choses similaires à ce que dans le passé, cependant, et il y a quelques draw-backs:

  • La réflexion peut être plus lent que tout en spécifiant tout, combien dépend, et il pourrait ne pas être un problème pour vous à tout. Le plus gros problème pour moi est simplement que vous risquez plus d'erreurs d'exécution que d'erreurs lors de la compilation, économisant ainsi du temps à l'avance, mais pouvant présenter des bogues gênants à long terme.

La seule chose que je dirais certainement à faire est de vous assurer d'utiliser try/catch/finally, essayez/enfin, ou envelopper SqlConnection, SqlCommand et SqlDataReader à l'intérieur en utilisant() s. Je viens de passer 2 jours à refactoring car les développeurs précédents ne fermaient aucune connexion ou datareader, et le pool de connexions explosait et refusait les connexions.

+0

Ceci est quelque chose mis ensemble rapidement à la recherche d'une solution. Je vais ajouter une vérification d'erreur et plus tard. Je ne suis même pas sûr que je vais l'utiliser. D'après les réponses que j'ai obtenues jusqu'à présent, il semble que l'utilisation de la réflexion soit une mauvaise idée. – jangeador

1

Bien que cette approche fonctionne, vous voudrez certainement ajouter une gestion des erreurs.

Il existe également des bibliothèques existantes qui le feraient pour vous, comme AutoMapper. Vous pouvez également regarder dans d'autres ORM, comme SubSonic, Linq2SQL, EntityFramework, NHibernate, etc ...

Notez également que la réflexion est très lente, en particulier le faire encore et encore comme ceci. Si cela devait se faire dans un grand système de charge lourde d'entreprise, il serait préférable de générer une méthode dynamique et un code informatique pour faire le mappage la première fois que le mappage est rencontré, puis de réexécuter la même méthode dynamique encore et encore. , au lieu de compter sur la réflexion.

+0

Merci pour votre contribution. Pouvez-vous s'il vous plaît fournir plus d'informations sur la génération d'une méthode dynamique dans ce cas? – jangeador

+1

Je ne me souviens pas d'où je viens de savoir comment faire, mais vous pouvez google quelque chose comme "méthodes dynamiques .net" ou regarder les documents MSDN pour l'espace de noms System.Reflection.Emit ", principalement les classes DynamicMethod et ILGenerator Emettre l'IL à la volée peut être assez ennuyeux et difficile à déboguer, mais a un gros gain de vitesse à la fin. – CodingWithSpike

Questions connexes