Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CsvReader not recognising different registered class maps #551

Closed
robertlarkins opened this issue Jul 22, 2016 · 2 comments
Closed

CsvReader not recognising different registered class maps #551

robertlarkins opened this issue Jul 22, 2016 · 2 comments

Comments

@robertlarkins
Copy link

I'm using CsvHelper v2.16.0 to try and read a csv file with different record types:

PlaceName,Longitude,Latitude,Elevation
NameString,123.456,56.78,40

Date,Count
1/1/2012,1
2/1/2012,3
3/1/2012,10
4/2/2012,6

but I'm getting a CsvMissingFieldException saying that Fields 'Date' do not exist in the CSV file. I have two definition and map classes, one for the location and the other for the counts, which are:

public class LocationDefinition
{
    public string PlaceName { get; set; }
    public double Longitude { get; set; }
    public double Latitude { get; set; }
    public double Elevation { get; set; }
}

public sealed class LocationMap : CsvClassMap<LocationDefinition>
{
    public LocationMap()
    {
        Map(m => m.PlaceName).Name("PlaceName");
        Map(m => m.Longitude).Name("Longitude");
        Map(m => m.Latitude).Name("Latitude");
        Map(m => m.Elevation).Name("Elevation");
    }            
}     

public class CountDefinition
{
    public DateTime Date { get; set; }
    public int Count { get; set; }
}

public sealed class CountMap : CsvClassMap<CountDefinition>
{
    public CountMap()
    {
        Map(m => m.Date).Name("Date");
        Map(m => m.Count).Name("Count");
    }
}

The code that I have for reading the csv file is:

LocationDefinition Location;
var Counts = new List<CountDefinition>();

using (TextReader fileReader = File.OpenText(@"Path\To\CsvFile"))
using (var csvReader = new CsvReader(fileReader))
{
    csvReader.Configuration.RegisterClassMap<LocationMap>();
    csvReader.Configuration.RegisterClassMap<CountMap>();

    // Only reads a single line of Location data
    csvReader.Read();
    LocationData = csvReader.GetRecord<LocationDefinition>();
    csvReader.Read(); // skip blank line
    csvReader.Read(); // skip second header section

    // Read count data records
    while (csvReader.Read())
    {
        var tempCount = csvReader.GetRecord<CountDefinition>();
        Counts.Add(tempCount);
    }
}

The exception gets thrown on the tempCount line. From what I can tell it still expects a Location record, but I would have thought GetRecord<CountDefinition> would specify the record type. I've also tried ClearRecordCache and unregistering the LocationMap to no avail.

Is this an issue with CsvHelper, or (more likely) a problem with how I am using CsvReader?

@JoshClose
Copy link
Owner

Since you don't have a single header, you'll need to ignore headers and use indexes instead. This brings up an idea though. I could have the ReadHeader method parse headers for a specific record type.

Here is an example that should work for you though.

void Main()
{
    LocationDefinition Location;
    var Counts = new List<CountDefinition>();

    using (var stream = new MemoryStream())
    using (var reader = new StreamReader(stream))
    using (var writer = new StreamWriter(stream))
    using (var csvReader = new CsvReader(reader))
    {
        writer.WriteLine("PlaceName,Longitude,Latitude,Elevation");
        writer.WriteLine("NameString,123.456,56.78,40");
        writer.WriteLine();
        writer.WriteLine("Date,Count");
        writer.WriteLine("1/1/2012,1");
        writer.WriteLine("2/1/2012,3");
        writer.WriteLine("3/1/2012,10");
        writer.WriteLine("4/2/2012,6");
        writer.Flush();
        stream.Position = 0;

        csvReader.Configuration.HasHeaderRecord = false;
        csvReader.Configuration.RegisterClassMap<LocationMap>();
        csvReader.Configuration.RegisterClassMap<CountMap>();

        csvReader.Read(); // get header
        csvReader.Read(); // get first record
        var locationData = csvReader.GetRecord<LocationDefinition>();

        csvReader.Read(); // skip blank line
        csvReader.Read(); // skip second header section

        // Read count data records
        while (csvReader.Read())
        {
            var tempCount = csvReader.GetRecord<CountDefinition>();         
            Counts.Add(tempCount);
        }
    }
}

public class LocationDefinition
{
    public string PlaceName { get; set; }
    public double Longitude { get; set; }
    public double Latitude { get; set; }
    public double Elevation { get; set; }
}

public sealed class LocationMap : CsvClassMap<LocationDefinition>
{
    public LocationMap()
    {
        Map(m => m.PlaceName);
        Map(m => m.Longitude);
        Map(m => m.Latitude);
        Map(m => m.Elevation);
    }
}

public class CountDefinition
{
    public DateTime Date { get; set; }
    public int Count { get; set; }
}

public sealed class CountMap : CsvClassMap<CountDefinition>
{
    public CountMap()
    {
        Map(m => m.Date);
        Map(m => m.Count);
    }
}

@JoshClose
Copy link
Owner

I added a feature issue to make this work better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants