2010-02-12 10 views
1

J'ai construit une enveloppe autour de NpgSQL pour un tas de méthodes que j'utilise habituellement dans le DAL de mes projets. Deux d'entre eux, j'utilise habituellement pour remplir des DTO directement à partir d'un DataReader. Habituellement, dans une méthode d'assistant de remplissage, j'instancie le DTO et je parcourt les propriétés qui mappent les données du Datareader à la propriété correspondante. La méthode de remplissage est générée la plupart du temps.NpgSQLdataReader GetOrdinal jeter des exceptions .. n'importe comment?

Puisque j'autorise la plupart des propriétés à être nulles ou à utiliser les valeurs par défaut du DTO, j'ai utilisé une méthode pour vérifier si les données de dataReader sont valides pour la propriété avant de remplir la propriété. Donc, je vais avoir un IsValidString (« fieldname ») et méthodes DRGetString (« fieldname »), comme suit:

public bool IsValidString(string fieldName) 
{ 
     if (data.GetOrdinal(fieldName) != -1 
      && !data.IsDBNull(data.GetOrdinal(fieldName))) 
      return true; 
     else 
      return false; 
} 

public string DRGetString(string fieldName) 
{ 
     return data.GetString(data.GetOrdinal(fieldName)); 
} 

Ma méthode de remplissage est delagated à toute méthode exécutée la requête et ressemble à:

public static object FillObject(DataParse<PostgreSQLDBDataParse> dataParser) 
{ 
    TipoFase obj = new TipoFase(); 

    if (dataParser.IsValidInt32("T_TipoFase")) 
     obj.T_TipoFase = dataParser.DRGetInt32("T_TipoFase"); 

    if (dataParser.IsValidString("NM_TipoFase")) 
     obj.NM_TipoFase = dataParser.DRGetString("NM_TipoFase"); 

      //...rest of the properties .. this is usually autogenerated by a T4 template 

    return obj; 
} 

Cela fonctionnait bien et dandy dans NpgSQL pre 2.02. . Lorsque la méthode GetOrdinal a été appelée, et si le champ était inexistant dans dataReader, j'obtiendrais simplement un -1 retourné. Facile à retourner false dans IsValidString() et passez simplement à la propriété suivante. Le coup de performance de la vérification des champs inexistants était pratiquement négligeable.

Malheureusement, les modifications apportées à NpgSQL font que GetOrdinal génère une exception lorsque le champ n'existe pas. J'ai une solution de contournement simple dans laquelle j'emballe le code dans un try/catch et lance false dans le catch. Mais je peux sentir le coup dans la performance, surtout quand je vais en mode débogage. Remplir une longue liste prend quelques minutes. En fait, NpgSQL a un paramètre qui peut être ajouté à la chaîne de connexion (Compatibilité) pour supporter la compatibilité ascendante de cette méthode, mais je n'ai jamais réussi à le faire fonctionner correctement (je reçois toujours une exception à cause d'un mal formé). chaîne de connexion). Quoi qu'il en soit, je cherche des suggestions pour de meilleures solutions de contournement. Une meilleure façon de remplir l'objet à partir du lecteur de données ou même de contourner le problème d'exception?

Répondre

0

J'ai créé une solution à mon problème, qui ne nécessite pas de grands changements, et présente des performances intéressantes (ou semble-t-il). Peut-être juste une nouvelle bibliothèque/wrapper d'analyse. Fondamentalement, je vais parcourir les champs de dataReader, et copiez chacun dans une collection (dans mon cas, une liste). Ensuite, je vais vérifier les données valides et si cela est valide, je vais copier les données à la propriété de l'objet.

Je vais donc:

public class ParserFields 
{ 
    public string FieldName { get; set; } 
    public Type FieldType { get; set; } 
    public object Data { get; set; } 
} 

et je vais remplir l'objet en utilisant:

public static object FillObjectHashed(DataParse<PostgreSQLDBDataParse> dataParser) 
    { 
     //The the Field list with field type and data 
     List<ParserFields> pflist = dataParser.GetReaderFieldList(); 

     //create resulting object instance 
     CandidatoExtendido obj = new CandidatoExtendido(); 

     //check for existing field and valid data and create object 
     ParserFields pfdt = pflist.Find(objt => objt.FieldName == "NS_Candidato"); 
     if (pfdt != null && pfdt.FieldType == typeof(int) && pfdt.Data.ToString() != String.Empty) 
      obj.NS_Candidato = (int)pfdt.Data; 

     pfdt = pflist.Find(objt => objt.FieldName == "NM_Candidato"); 
     if (pfdt != null && pfdt.FieldType == typeof(string) && pfdt.Data.ToString() != String.Empty) 
      obj.NM_Candidato = (string)pfdt.Data; 

     pfdt = pflist.Find(objt => objt.FieldName == "Z_Nasc"); 
     if (pfdt != null && pfdt.FieldType == typeof(DateTime) && pfdt.Data.ToString() != String.Empty) 
      obj.Z_Nasc = (DateTime)pfdt.Data; 

     //... 

     return obj; 
    } 

je chronométré mes variations, pour voir les diférences. A fait une recherche qui a retourné 612 résultats. J'ai d'abord interrogé deux fois la base de données pour prendre en compte la première exécution de la requête et les diférences subséquentes liées à la mise en cache (et ce qui était assez significatif). Ma méthode FillObject a simplement créé une nouvelle instance de l'objet désiré à ajouter à la liste des résultats.

  • 1ère requête à la liste des instances de l'objet: 2896K tiques
  • 2ème requête (comme première): 1141K tiques

J'ai essayé d'utiliser le remplissage précédent objets

  • To Liste de l'objet désiré, rempli avec les données de retour ou par défaut, vérifiant toutes les propriétés des objets: 3323K tiques
  • à la liste des objets désirés, en vérifiant les propriétés que l'objet retourné dans la recherche: 1127K tiques
  • à la liste des objets désirés, en utilisant la liste de recherche, de vérifier que les champs retournés: 1097K tiques
  • à la liste des objets désirés, en utilisant la liste de recherche, de vérifier tous les champs (moins quelques propriétés imbriquées): 1107K tiques

L'original Le code que j'utilisais consommait presque 3 fois plus de tiques que lorsque j'utilisais une méthode limitée aux champs désirés. Les excpetions où le tuer. Avec le nouveau code pour la méthode fillobject, le surcoût de vérification des champs inexistants est minime comparé à la simple vérification des champs désirés.

Cela semble fonctionner, pour l'instant au moins. Peut-être essayer de chercher quelques optimisations. Toute suggestion sera appréciée!

Questions connexes