Dynamically create columns using csvHelper

I have a worker with various fields that are retrieved from the server. I am using the CSVHelper package to convert this class to an excel sheet. The worker has fields like:

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

I can display the name, phone, number, for example

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

And I create a map:

 csv.Configuration.RegisterClassMap<WorkerMap>(); 

Write a list of employees:

 csv.WriteRecords(workerList); 

How can I map a customerField dictionary to an excel sheet so that the key (row) is another column name and the value (object) is the column value.

Does CSVHelper do this at runtime. I looked through the documentation. Could not find anything that would work for me.

+6
source share
2 answers

I do not think the dictionary is currently supported. First, CsvHelper would have a hard time knowing which headers to write. Fortunately, it is not too complicated to use CsvWriter manually, writing the field at a time. Assuming each Worker has the same keys in customerField , then your code might look something like this.

 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(); } 

This code is not tested, but should make you pretty close to the behavior you need. If customerField dictionary keys are not compatible in the list, then the code will be a little more complicated, but it will still resolve.

+4
source

The dictionary is not supported, but ExpandoObject is supported.

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

If you follow the first link above, you will find the WriteDynamicHeader method used on lines 50 and 57.

Using the extension method, I create an ExpandoObject for each record and use CsvHelper to write this object. The Dictionary<string, object> parameter named document is what I want to create a CSV record.

 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); } } } 

Now I can create an ExpandoObject from my dictionary like this

 var csvObj = myDictonary.BuildCsvObject(); 

and yet, after the Josh tests in the link above, we have everything we need to use the dictionary pretty easily with CsvHelper. I don't think this is the best solution for Michael, just a different approach.

loan, for which the basic ExpandoObject from the dictionary code should be provided (there is much more explanation here!) https://www.oreilly.com/learning/building-c-objects-dynamically

+1
source

Source: https://habr.com/ru/post/1014834/


All Articles