web-dev-qa-db-fra.com

Création dynamique de colonnes avec l'aide de csvHelper

J'ai un ouvrier avec divers champs qui sont récupérés du serveur. J'utilise le package CSVHelper pour convertir cette classe en feuille Excel. Le travailleur a des champs comme:

class Worker
{ 
string name;
string phone;
string age;
Dictionary<string,object> customerField;
}

Je peux mapper le nom, le téléphone, le numéro comme

class WorkerMap : CsvClassMap<Worker>
{
public WorkerMap()
{
Map(m => m.name);
Map(m => m.phone);
Map(m => m.age);
}
}

Et je génère la carte en:

csv.Configuration.RegisterClassMap<WorkerMap>();

Rédigez la liste des travailleurs par:

csv.WriteRecords(workerList);

Comment mapper le dictionnaire customerField sur la feuille Excel de telle sorte que la clé (chaîne) soit un autre nom de colonne et que la valeur (objet) soit la valeur de la colonne.

Est-ce que CSVHelper nous aide à le faire au moment de l'exécution? J'ai parcouru la documentation. Impossible de trouver quelque chose qui a fonctionné pour moi.

7
hyoyin_Kyuoma

Je ne pense pas que l'écriture d'un dictionnaire est supportée pour le moment. D'une part, CsvHelper aurait du mal à savoir quelles en-têtes écrire. Heureusement, utiliser CsvWriter manuellement, en écrivant un champ à la fois, n’est pas trop complexe. Si nous supposons que chaque utilisateur a les mêmes clés dans customerField, votre code pourrait alors ressembler à ceci.

var firstWorker = workerList.First();
var keys = firstWorker.customerField.Keys.ToList();

var headers = new []{ "name", "phone", "age"}.Concat(keys).ToList();
var csv = new CsvWriter( textWriter );

// Write the headers
foreach( var header in headers )
{
    csv.WriteField(header);
}
csv.NextRecord();

// Write the rows
foreach( var item in workerList)
{
    csv.WriteField(item.name);
    csv.WriteField(item.phone);
    csv.WriteField(item.age);
    var dict = worker.customerField;
    foreach (var key in keys)
    {
        csv.WriteField(dict[key]);
    }
    csv.NextRecord();
}

Ce code n'a pas été testé, mais devrait vous rapprocher du comportement dont vous avez besoin. Si les clés du dictionnaire customerField ne sont pas cohérentes dans la liste, le code serait un peu plus compliqué, mais il reste résolu.

8
Michael Richardson

Le dictionnaire n'est pas pris en charge, mais ExpandoObject est pris en charge.

https://github.com/JoshClose/CsvHelper/blob/48e70742e06007dae3a635c418b7e3358f667c4f/src/CsvHelper.Tests/Writing/MultipleHeadersTest.cs

https://github.com/JoshClose/CsvHelper/blob/b74a2f95a101158f4cdedd25fae6e8392b58855b/src/CsvHelper.Tests/Writing/DynamicTests.cs

Si vous suivez le premier lien ci-dessus, vous trouverez la méthode WriteDynamicHeader utilisée sur les lignes 50 et 57.

Avec l’aide d’une méthode d’extension, je crée un ExpandoObject pour chaque enregistrement et utilise CsvHelper pour écrire cet objet.Le paramètre Dictionary<string, object> nommé document correspond à ce que je souhaite créer l’enregistrement CSV.

public static class DictionaryCsvExtentions
{
    public static dynamic BuildCsvObject(this Dictionary<string, object> document)
    {
        dynamic csvObj = new ExpandoObject();

        foreach (var p in document)
        {
            AddProperty(csvObj, p.Key, p.Value);
        }

        return csvObj;
    }

    private static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue)
    {
        var expandoDict = expando as IDictionary<string, object>;
        if (expandoDict.ContainsKey(propertyName))
        {
            expandoDict[propertyName] = propertyValue;
        }
        else
        {
            expandoDict.Add(propertyName, propertyValue);
        }
    }
}

Maintenant, je peux créer un ExpandoObject à partir de mon dictionnaire comme ceci

var csvObj = myDictonary.BuildCsvObject();

et avec cela, après les tests de Josh dans le lien ci-dessus, nous avons tout ce dont nous avons besoin pour utiliser un dictionnaire de manière assez transparente avec CsvHelper. Je ne pense pas que ce soit une meilleure solution pour Michael, mais une approche différente.

crédit où crédit est dû à la base ExpandoObject du code de dictionnaire (à partir duquel il existe beaucoup plus d'explications!) https://www.oreilly.com/learning/building-c-objects-dynamically

2
robs