0

I have a CSV with a single Header row. Some of the columns of each row need to map to one class while other columns of the row need to map to a different class.

I tried this but with no success:

using(var reader = new StreamReader(@"c:\temp\myfile.csv"))
{
    using(var csv = new CsvReader(reader))
    {
       csv.Configuration.RegisterClassMap<ClientMap>();
       csv.Configuration.RegisterClassMap<BookingMap>();

       var bookings = csv.GetRecords<Booking>();
       ... //iterate over bookings and write to Console

       reader.BaseStream.Position = 0;

       var clients = csv.GetRecords<Client>();
       ... //iterate over clients and write to Console
    }
}

Classes

public class Client {
   public string Firstname {get; set;}
   public string Lastname {get; set;}
   public AgesEnum Age {get; set;}
}

public class Booking {
    public string ExternalId {get; set;}
    public string Status {get; set;}
}

Maps

public class ClientMap : ClassMap<Client> 
{
   public ClientMap()
   {
       Map(m => m.Firstname).Name("FIRSTNAM");
       Map(m => m.Lastname).Name("LASTNAME");
       Map(m => m.Age).ConvertUsing(row =>{
          var age = row.GetField<int>("AGE");

          if(age < 2)
             return AgesEnum.Baby;
          if(age < 10)
             return AgesEnum.Young;
          if(age < 40)
             return AgesEnum.Middle;
          return AgesEnum.Old;
       } );
    }
}


public BookingMap : ClassMap<Booking>
{
    public BookingMap()
    {
        Map(b => b.ExternalId).Name("SYSID");
        Map(b => b.Status);
    }
}

What happens when I run this is that the bookings get returned fine and I can iterate over them. However, I get an error on the GetRecords<Client>() line stating that

The conversion cannot be performed. Text: 'Age' MemberType: TypeConverter: 'CsvHelper.TypeConversion.Int32Converter'

If I comment out all the code relating to Bookings and only perform the GetRecords<Client>(), I get no error.

Why won't this work? Do I have to set up a whole new StreamReader?

RHarris
  • 10,641
  • 13
  • 59
  • 103
  • Is it possible that you are missing a (int) cast at some point? I'm not sure CsvHelper can convert custom enums. Either that or your custom "AgesEnum" does not have a Int value for each possible string. – Michaël Corriveau-Côté May 17 '19 at 17:40

2 Answers2

0

I think you may find something interesting regarding using Enums with CsvHelper right here

  • I don't think that's apples to apples. I'm not trying to convert a value read from the CSV into a matching Enum value. There really is no casting or conversion going on -- I'm simply setting an enum value based on some other value in the CSV. Plus, the code does work as long as I don't do the booking conversion first. – RHarris May 17 '19 at 18:17
  • Are you able to see in Debug the data inside the StreamReader? Has it changed after doing the Booking conversion? What happens to the object when you set the position to 0? – Michaël Corriveau-Côté May 17 '19 at 18:32
0

The problem is you are setting the stream position back to the beginning and CsvReader thinks you already read the header when you got the bookings, so it reads the first line again as data instead of as the header. You need to manually read the header again.

using(var reader = new StreamReader(@"c:\temp\myfile.csv"))
{
    using(var csv = new CsvReader(reader))
    {
       csv.Configuration.RegisterClassMap<ClientMap>();
       csv.Configuration.RegisterClassMap<BookingMap>();

       var bookings = csv.GetRecords<Booking>();
       ... //iterate over bookings and write to Console

       reader.BaseStream.Position = 0;

       csv.Read();
       csv.ReadHeader();

       var clients = csv.GetRecords<Client>();
       ... //iterate over clients and write to Console
    }
}
David Specht
  • 7,784
  • 1
  • 22
  • 30