Search code examples
c#npoi

Can NPOI Mapper set the row number


I'm currently using npoi.mapper in c# to read an excel file into poco classes for further processing and it is all working very well.

The system has grown and several spreadsheets are often processed in parrallel I would thefore like to include the filename and row number in my poco class to use for debugging purposes.

So far I've just added the filename and row number in by hand in a for loop but was wondering if I could refactor & clean up my code by having npoi.mapper do this for me?

heres my code:

   var mapper = new Mapper(excelStream);
   var rows = mapper.Take<MyPocoClass>("Sheet2");

   for(int i = 0; i < rows.Length; i++)
   {
       var row = rows[i];

       row.Filename = excelName;
       row.RowNumber = i;
   } 

I've read the documentation over on the GitHub Page and it sounds like I should be using a custom resolver, but I cannot see how to access the row number as part of that?


Solution

  • I take a look at the Mapper.cs on github and I realized that the RowInfo and IRowInfo classes (That holds the row number) are only used on returns of the public methods.

    On the extensions folder I found an ExtensionMethod of IEnumerable<T> called ForEach<T> at class EnumerableExtensions that could be used as an alternative for your current code.

    This is a non tested solution.

       var mapper = new Mapper(excelStream);
       var rows = mapper.Take<MyPocoClass>("Sheet2");
    
       rows.Foreach<RowInfo<MyPocoClass>>(row => {
            row.Value.Filename = "Sheet2";
            row.Value.RowNumber = row.RowNumber;
       });
    

    This is just a sintatic sugar for your current code.


    In my opinion the best approach for that kind of job would fllow this steps:

    1) Create an interface or a base type that contains the properties Filename and RowNumber. Ex of base type:

    public class MyPocoFromExcelBase 
    {
        public string FileName { get; set; }
    
        public int RowNumber { get; set; }
    }
    

    2) Inherit MyPocoFromExcelBase on your MyPocoClass and any other class that represents a row from an excel file.

    3) Create a Extension Method for IEnumerable<RowInfo<MyPocoFromExcelBase>> and do the mapping:

        public static void MapRowNumber(this IEnumerable<RowInfo<MyPocoFromExcelBase>> sequence, string fileName)
        {
            if (sequence == null) return;
    
            foreach (var item in sequence)
            {
                item.Value.Filename = fileName;
                item.Value.RowNumber = item.RowNumber;
            }
        }
    

    4) Then you can do something like this in any mapper:

    var mapper = new Mapper(excelStream);
    var rows = mapper.Take<MyPocoClass>("Sheet2");
    rows.MapRowNumber("Sheet2");
    

    This way you will not need to rewrite this logic all over your code.