Search code examples
c#.net-6.0csvhelper

CSV EnumerateRecords returning same row multiple times in .NET 6


I am using C# console application to read a .CSV file, process it and save the data into a database. While reading the code, I get the correct number of records, but all records are of the last record.

So for example, the file has 50 records and first column of last row is Shane, the record in the below code will have 50 rows but each with the data from Shane row.

using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Configuration.TrimOptions = CsvHelper.Configuration.TrimOptions.Trim;
    var obj = new Students();
    var records = csv.EnumerateRecords(obj); //Reads correct number of records but its only the last record multiple times.
}

What am I missing?


Solution

  • The problem, as others have commented, is that if you do something to enumerate your records, like calling records.ToList(), your list is now full of references to the same obj, var obj = new Students();.

    • Calling csv.GetRecords<Student>().ToList() is like having a notebook and writing out each record on each page. And your list looks like:
    [0] see page1
    [1] see page2
    [2] see page3
    
    • Calling csv.EnumerateRecords(obj).ToList() is like having a single sheet of paper and you use erasable ink or pencil for the actual data. As CsvReader gives you the records, it takes less time to write them out because you don't have to write out FirstName: Foo, LastName: Bar, you can just erase the Foo and the Bar and write in the new data. But now your list looks like:
    [0] see page1
    [1] see page1
    [2] see page1
    

    And your var obj has now been overwritten with the last record that was yielded by CsvReader.

    If you wanted to save each individual record using EnumerateRecord, you would need to save them as they were being enumerated.

    var records = csv.EnumerateRecords(obj);
    foreach (var record in records)
    {
        // Save record to database here.
    }
    

    Here is another way to see that you are looking at a list of the same object.

    void Main()
    {
        var record1 = new Foo{ Id = 1, Name = "Fred"};
        var record2 = new Foo{ Id = 1, Name = "Fred"};
        var record3 = record1;
    
        Console.WriteLine("record1 == record2: " + (record1 == record2));
        Console.WriteLine("record1 == record3: " + (record1 == record3));
    
        using (var reader = new StringReader("Id,Name\n1,Fred\n1,Fred"))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            var records = csv.GetRecords<Foo>().ToList();
    
            Console.WriteLine("records[0] == records[1]: " + (records[0] == records[1]) + " (GetRecords)");
        }
    
        using (var reader = new StringReader("Id,Name\n1,Fred\n1,Fred"))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            var record = new Foo();
            var records = csv.EnumerateRecords(record).ToList();
    
            Console.WriteLine("records[0] == records[1]: " + (records[0] == records[1]) + " (EnumerateRecords)");
        }
    }
    
    // You can define other methods, fields, classes and namespaces here
    public class Foo
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    

    Outputs

    record1 == record2: False
    record1 == record3: True
    records[0] == records[1]: False (GetRecords)
    records[0] == records[1]: True (EnumerateRecords)