2010-01-15 2 views
2

J'utilise MySQL Connector/Net et je veux écrire une requête sur une table dont le nom sera spécifié lors de l'exécution.Quelle est la meilleure façon de choisir un nom de table dynamiquement à l'exécution?

Cet exemple est du haut de ma tête (non testé):

public class DataAccess 
{ 
    public enum LookupTable 
    { 
     Table1, 
     Table2, 
     Table3 
    } 

    public int GetLookupTableRowCount(LookupTable table) 
    { 
     string tableName = string.Empty; 

     switch (table) 
     { 
      case LookupTable.Table1: 
       tableName = "table_1"; 
       break; 
      case LookupTable.Table2: 
       tableName = "table_2"; 
       break; 
      case LookupTable.Table3: 
       tableName = "table_3"; 
       break; 
      default: 
       throw new ApplicationException("Invalid lookup table specified."); 
     } 

     string commandText = string.Concat("SELECT COUNT(*) FROM ", tableName); 

    // Query gets executed and function returns a value here... 
    } 
} 

Depuis que je ne pense pas que vous pouvez paramétrer un nom de table dans une requête, j'ai utilisé un ENUM plutôt qu'une chaîne en le paramètre de la fonction pour limiter la possibilité de SQL injection.

Est-ce que sembler une bonne approche? Y a-t-il un meilleur moyen?

+0

Est-ce que .net ne supporte pas l'ajout de propriétés supplémentaires au type enum? – Jherico

+0

Voulez-vous dire comme Table1 = "table_1", etc. Si oui, alors vous ne pouvez utiliser que des types entiers comme int, et long. –

Répondre

4

Vous ne pouvez pas paramétrer un identifier (nom de table ou nom de champ) dans MySQL, cependant, vous pouvez leur échapper en utilisant des guillemets.

La requête suivante se déroulera en toute sécurité, mais produire une erreur car la table n'existe pas (à moins que par hasard bizarre que vous avez réellement une table nommée comme celui-ci):

SELECT * FROM `users; DROP TABLE users;`; 

Fondamentalement, vous pouvez utiliser dynamique noms ou champs tant qu'ils sont entourés en arrière. Afin d'éviter l'injection SQL de cette façon, tout ce que vous devez faire est de dépouiller les contre-apostrophes premier:

tableName = tableName.Replace("`", ""); 
string commandText = "SELECT COUNT(*) FROM `" + tableName + "`"; 
+0

Je vois ce que vous dites, mais je pense que je suis plus sûr d'isoler mon texte de requête de toutes les entrées de forme libre. C'est pourquoi je ne voulais pas utiliser un paramètre de chaîne dans ma méthode d'accès aux données. –

+0

Eh bien, je ne peux pas vous faire confiance dans la sémantique de la langue. Vous faites confiance au backtick et aux méthodes d'échappement de MySQL ou vous ne le faites pas.L'alternative est de coupler votre structure de base de données à votre code via une sorte de table de recherche comme d'autres l'ont suggéré, ce que je trouve personnellement très désagréable. – zombat

+0

Je vous suggère en fait de lire attentivement cette page sur les identificateurs, car elle indique ce qu'est un identificateur valide. Si vous vouliez une protection supplémentaire, vous pouvez toujours appliquer uniquement des caractères alphanumériques ou même demander si la table existait auparavant. Cependant, MySQL gérera tout caractère invalide dans un identifiant en lançant une erreur sur la requête. – zombat

1

droit, vous ne pouvez pas utiliser un paramètre de requête pour un nom de table, un nom de colonne, un mot-clé SQL ou une expression, etc. Vous pouvez utiliser un paramètre de requête uniquement pour une seule valeur.

Je suis d'accord que faire une sorte de cartographie de l'entrée au nom de la table littérale est une bonne façon de protéger contre l'injection SQL.

Je ne ai pas dans le programme .NET, je l'habitude d'utiliser des langages dynamiques comme PHP, Python ou Perl. Donc j'utilise un tableau de hachage. Vous pouvez ignorer le switch() si vous pouvez simplement utiliser votre variable d'énumération pour indexer dans le tableau de hachage.

$tableName = $tableNameHash[ $table ]; 

Est-ce que .NET prend en charge une structure de données de type hash-map? C'est ce que je chercherais.


On dirait qu'il ya une classe hash_map dans la bibliothèque standard C.

+0

Oui, il existe des hashtables et des dictionnaires et beaucoup d'autres classes de style de collection dans .NET. J'aime ta suggestion. –

2

noms de tables dynamiques ne sont jamais une bonne approche (à moins que vous développez un PHPMyAdmin ou quelque chose de similaire).

Si les noms vous de table sont limitées, pourquoi avez-vous tout simplement pas une procédure stockée et appelez avec un paramètre?

DECLARE _which INT 
BEGIN 
     SELECT COUNT(*) 
     FROM table_1 
     WHERE _which = 1 
     UNION ALL 
     SELECT COUNT(*) 
     FROM table_2 
     WHERE _which = 2 
     UNION ALL 
     SELECT COUNT(*) 
     FROM table_3 
     WHERE _which = 3 
END 
+3

Je ne suis pas d'accord avec "jamais une bonne approche". Les applications de grande entreprise utiliseront presque certainement un système de dénomination dynamique pour fractionner les données en ensembles gérables. Les techniques de fragmentation de base de données utiliseront même des noms de bases de données dynamiques *, et pas seulement des tables. – zombat

Questions connexes