Est-il préférable d'utiliser le nom de la colonne ou l'index de la colonne sur .Net DataSets?

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

Question

Lors de la récupération des valeurs d'un DataRow, est-il préférable d'utiliser le nom ou l'index de la colonne?

Le nom de la colonne est plus lisible et plus facile à gérer:

int price = (int)dr["Price"];

Alors que l'index de la colonne est juste plus rapide (je pense):

int price = (int)dr[3];

L'utilisation des noms de colonne serait-elle brisée si vous décidiez de brouiller la base de données?

Était-ce utile?

La solution

Je préfère généralement la lisibilité et la compréhension à la vitesse. Allez avec le nom. Vous pouvez (devriez) utiliser des constantes de chaîne pouvant être mises à jour à un endroit unique si vous décidez de modifier les noms des colonnes de la base de données.

Autres conseils

L'accès aux valeurs de colonnes / lignes via les noms de colonnes est préférable pour la lecture humaine et la compatibilité en aval (si à l'avenir quelqu'un change l'ordre ou le nombre de colonnes).

Accepter des valeurs de colonnes / lignes via des index de colonnes est meilleur pour la performance.

Donc, si vous voulez changer une valeur dans une / deux / ..... lignes, les noms des colonnes sont ok. Mais si vous souhaitez modifier une valeur dans des milliers de lignes, vous devez utiliser l'index de colonne calculé à partir du nom de la colonne:

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

Complètement agressif avec les autres re. allez pour la lisibilité et la maintenabilité sur la vitesse. Cependant, j’avais une méthode générique qui nécessitait que les colonnes nommées soient transmises en tant que paramètres. Il était donc logique de déterminer les index des colonnes.

Dans l'analyse comparative ci-dessous, l'utilisation de l'index de la colonne a montré une grande amélioration. Par conséquent, s'il s'agit d'un goulet d'étranglement ou d'une partie critique de votre code, il peut en valoir la peine.

La sortie du code ci-dessous est:

515ms avec ColumnIndex

1031ms avec ColumnName

    static void Main(string[] args)
    {            
        DataTable dt = GetDataTable(10000, 500);
        string[] columnNames = GetColumnNames(dt);

        DateTime start = DateTime.Now;
        TestPerformance(dt, columnNames, true);

        TimeSpan ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnIndex\r\n", ts.TotalMilliseconds);

        start = DateTime.Now;
        TestPerformance(dt, columnNames, false);
        ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnName\r\n", ts.TotalMilliseconds);
    }

    private static DataTable GetDataTable(int rows, int columns)
    {
        DataTable dt = new DataTable();

        for (int j = 0; j < columns; j++)
        {
            dt.Columns.Add("Column" + j.ToString(), typeof(Double));
        }

        Random random = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < rows; i++)
        {
            object[] rowValues = new object[columns];

            for (int j = 0; j < columns; j++)
            {
                rowValues[j] = random.NextDouble();
            }

            dt.Rows.Add(rowValues);
        }

        return dt;
    }

    private static void TestPerformance(DataTable dt, string[] columnNames, bool useIndex)
    {
        object obj;
        DataRow row;

        for (int i =0; i < dt.Rows.Count; i++)
        {
            row = dt.Rows[i];

            for(int j = 0; j < dt.Columns.Count; j++)
            {
                if (useIndex)
                    obj = row[j];
                else
                    obj = row[columnNames[j]];
            }
        }
    }

    private static string[] GetColumnNames(DataTable dt)
    {
        string[] columnNames = new string[dt.Columns.Count];

        for (int j = 0; j < columnNames.Length; j++)
        {
            columnNames[j] = dt.Columns[j].ColumnName;
        }

        return columnNames;
    }

Je pense que le nom de la colonne est la meilleure solution. Il est plus facile de déterminer ce que vous tirez, et l'ordre des colonnes est déterminé par l'instruction select, qui peut changer un jour ou l'autre. On pourrait dire que le nom de la colonne pourrait aussi changer, mais je pense que ce serait beaucoup moins probable.

EDIT:

En fait, si vous vouliez vraiment utiliser les index de colonnes, vous pouvez créer des constantes des index de colonnes et nommer la constante le nom de la colonne. Donc:

PRIMARY_KEY_COLUMN_NAME_INDEX = 0

Cela permettrait au moins de le rendre lisible.

Cela dépend de ce dont vous avez besoin. Dans mon cas, la vitesse était primordiale, car j'effectuais un traitement intense sur des milliers de lignes dans un DataSet. J'ai donc choisi d'écrire un morceau de code mettant en cache les index de colonne par nom. Ensuite, dans le code de la boucle, j'ai utilisé les index mis en cache. Cela a entraîné une augmentation raisonnable des performances par rapport à l’utilisation directe du nom de la colonne.

Votre kilométrage peut varier, bien sûr. Ma situation était plutôt artificielle et inhabituelle, mais cela a plutôt bien fonctionné.

Mon avis est que vous ne devriez passer aux index que si vous avez profilé votre code et que celui-ci apparait comme un goulot d'étranglement. Je ne pense pas que cela se produira.

Nommer des trucs est bon, cela permet à notre cerveau limité de comprendre les problèmes et de créer des liens plus facilement. C'est pourquoi on nous donne des noms tels que Fred, Martin, Jamie, plutôt que Human [189333847], Human [138924342] et Human [239333546].

Si vous avez décidé de masquer la base de données en modifiant les noms de colonne ultérieurement, vous pouvez créer un alias pour les colonnes de votre requête afin que le code de l'indexeur reste fonctionnel. Je suggère d'indexer par nom.

Allez avec le nom, vous obtenez de meilleurs messages d'erreur:)

J'opte pour des chaînes pour une lecture facile et une facilité de maintenance. J'utilise des constantes de chaîne pour définir les valeurs des noms de colonne. Ex:

public class ExampleDataColumns
{
    public const string ID = "example_id";
    public const string Name = "example_name";
    ....    
}

Ensuite, je peux le référencer plus tard comme ceci:

row[ExampleDataColumns.ID]

Utilisez les noms de colonne pour DataRow de la même façon qu'un SGBDR ne gagnera pas en rapidité en obligeant les programmeurs à spécifier l'index de colonne en SQL. Mais vous pouvez peut-être imiter le fonctionnement d'un SGBDR lorsque vous émettez une instruction SELECT. Dans un moteur de SGBDR, il interroge l'index / le décalage de colonne des colonnes spécifiées dans la clause SELECT avant de parcourir les lignes, de sorte qu'il puisse fonctionner plus rapidement.

Si vous souhaitez vraiment gagner en rapidité, ne pas, utilisez la méthode const / enum (l'ordre des colonnes peut changer dans votre base de données ou votre couche ORM). Faites-le comme suggéré par TcKs (avant la boucle réelle):

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

pour moi, j'utilise la réflexion (je ne suis pas sûre que ce soit la bonne façon de nommer ce que je fais) pour obtenir le nom de la colonneColonne dans la table

non "codage en dur" est mieux

  int price = (int)dr[DatableVar.PriceColumn];
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top