Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use a ClassMap for writing with CsvHelper?

Tags:

csvhelper

I am attempting to use CsvHelper to improve my manual conversion process from objects to csv records/rows. I have created a complex ClassMap that I wanted to use to write a list of objects out to a file. How can I add the ClassMap to the CsvHelper instance's Configuration for writing?

I am getting the following exception and message now:

public class SpecimenMap : ClassMap<Specimen>
{
    public SpecimenMap()
    {
        Map(s =>
                DataFunctions.GetSiteByName(s.SiteName).RecordNo.ToString() + "-" +
                    s.SpecimenNumber.ToString()).
                    Index(0).Name("recordNumber");

        Map(s => 
                s.RecordNo.ToString()).
                    Index(1).Name("specimenNumber"); 

/* many more, but I set a breakpoint on the first 'Map' and it throws the exception. I also tried commenting out the first 'Map' and running the second (since the first includes calls to external functions), it had identical results. */ ....

        using (var writer = new StreamWriter(localFileLocation))
        using (var csv = new CsvWriter(writer))
        {
            csv.Configuration.RegisterClassMap<SpecimenMap>(); // this line throws exception
            csv.WriteRecords(specimen);
        }

Exception Thrown:

System.InvalidOperationException: No members were found in expression '{expression}'.

In my research I found this code but I don't know how to interpret the exception. Something about the Stack size after doing some kind of Reflection (Line 34). https://github.com/JoshClose/CsvHelper/blob/master/src/CsvHelper/Configuration/ClassMap%601.cs

like image 270
r3dfarce Avatar asked Apr 21 '19 21:04

r3dfarce


1 Answers

The error you are getting is telling you that the Map() function expects to only get a class member from it's expression. Map(s => s.SiteName). If you want to further manipulate the output, you can use ConvertUsing().

Updated for Version 27.2.1. ClassMap is registered on the Context and ConvertUsing() has been changed to Convert().

public static void Main(string[] args)
{    
    using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
    {
        var specimen = new List<Specimen> { new Specimen { SiteName = "DeepThought", SpecimenNumber = 1 } };

        csv.Context.RegisterClassMap<SpecimenMap>();

        csv.WriteRecords(specimen);

        Console.Read();
    }            
}

public class SpecimenMap : ClassMap<Specimen>
{
    public SpecimenMap()
    {
        Map(s => s.SiteName).Index(0).Name("recordNumber").Convert(s => GetSiteByName(s.Value.SiteName) + "-" + s.Value.SpecimenNumber);
        Map(s => s.SpecimenNumber).Index(1).Name("specimenNumber");
    }
}

public class Specimen
{
    public string SiteName { get; set; }
    public int SpecimenNumber { get; set; }
}

public static int GetSiteByName(string siteName)
{
    if (siteName == "DeepThought")
    {
        return 42;
    }

    return 1;
}

Original

public static void Main(string[] args)
{    
    using (var csv = new CsvWriter(Console.Out))
    {
        var specimen = new List<Specimen> { new Specimen { SiteName = "DeepThought", SpecimenNumber = 1 } };

        csv.Configuration.RegisterClassMap<SpecimenMap>();

        csv.WriteRecords(specimen);

        Console.ReadKey();
    }            
}

public class SpecimenMap : ClassMap<Specimen>
{
    public SpecimenMap()
    {
        Map(s => s.SiteName).Index(0).Name("recordNumber").ConvertUsing(s => GetSiteByName(s.SiteName) + "-" + s.SpecimenNumber);
        Map(s => s.SpecimenNumber).Index(1).Name("specimenNumber");
    }
}

public class Specimen
{
    public string SiteName { get; set; }
    public int SpecimenNumber { get; set; }
}

public static int GetSiteByName(string siteName)
{
    if (siteName == "DeepThought")
    {
        return 42;
    }

    return 1;
}
like image 107
David Specht Avatar answered Sep 30 '22 19:09

David Specht