Home > Back-end >  How to read an excel file where columns are repeated in a single row and convert them into datatable
How to read an excel file where columns are repeated in a single row and convert them into datatable

Time:10-08

I need to import an excel sheet and read the data and add this data to the database in ASP.NET Core MVC.

My table looks like this:

enter image description here

when I have the data in excel this format:

enter image description here

I'm able to read and add the data to database.

But I my Excel sheet is filled like this:

this

where the date is Day and Score and CutOf is in the single column header and these are repeating in a single row.

So how to read and convert them into a row basis for each guy and add them to the database?

var dt = new DataTable();

//Checking file content length and Extension must be .xlsx
if (file != null && file.ContentType.Length > 0 && System.IO.Path.GetExtension(file.FileName).ToLower() == ".xlsx")
{
    //Create a Folder.
    string path = Path.Combine(hostingEnv.WebRootPath, "Uploads");
    
    if (!Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    
    //Save the uploaded Excel file.
    string fileName = Path.GetFileName(file.FileName);
    string filePath = Path.Combine(path, fileName);

    using (var stream = new FileStream(filePath, FileMode.Create))
    {
        file.CopyTo(stream);
    }
    
    using (var workbook = new XLWorkbook(filePath))
    {
        IXLWorksheet worksheet = workbook.Worksheet(1);
        bool FirstRow = true;

        //Range for reading the cells based on the last cell used.
        string readRange = "1:1";
        
        foreach (IXLRow row in worksheet.RowsUsed())
        {
            //If Reading the First Row (used) then add them as column name
            if (FirstRow)
            {
                //Checking the Last cellused for column generation in datatable
                readRange = string.Format("{0}:{1}", 1, row.LastCellUsed().Address.ColumnNumber);
                
                foreach (IXLCell cell in row.Cells(readRange))
                {
                    dt.Columns.Add(cell.Value.ToString());
                }
                
                FirstRow = false;
            }
            else
            {
                //Adding a Row in datatable
                dt.Rows.Add();
                int cellIndex = 0;
                
                //Updating the values of datatable
                foreach (IXLCell cell in row.Cells(readRange))
                {
                    dt.Rows[dt.Rows.Count - 1][cellIndex] = cell.Value.ToString();
                    cellIndex  ;
                }
            }
        }
        
        //If no data in Excel file
        if (FirstRow)
        {
            ViewBag.Message = "Empty Excel File!";
        }

CodePudding user response:

Since you have a dynamic number of columns, it's really just a matter of looping through the columns and grabbing the values. I recreated this on my machine.

using System;
using System.Collections.Generic;
using ClosedXML.Excel;

namespace HelloDotNetCore
{
    class Program
    {
        static void Main(string[] args)
        {
            var scoreResults = new List<ScoreResult>();

            using (var workbook = new XLWorkbook("Scores.xlsx"))
            {
                var isHeaderRow = true;

                foreach (var row in workbook.Worksheet(1).RowsUsed())
                {
                    if (isHeaderRow)
                    {
                        isHeaderRow = false;
                        continue;
                    }

                    var name = row.Cell(1).GetString();

                    // This goes through the Date, Score column pairs until the end is reached for that row
                    for (int i = 2; i <= row.LastCellUsed().Address.ColumnNumber; i =2)
                    {
                        Console.WriteLine(row.Cell(i).GetString());

                        var scoreResult = new ScoreResult
                        {
                            Name = name,
                            DateTaken = row.Cell(i).GetDateTime(),
                            Score = row.Cell(i   1).GetValue<int>(),
                        };

                        scoreResults.Add(scoreResult);
                    }
                }
            }

            foreach (var s in scoreResults)
            {
                Console.WriteLine($"Name: {s.Name}, DateTaken: {s.DateTaken}, Score: {s.Score}");
            }
        }
    }

    class ScoreResult
    {
        public string Name { get; set; }

        public DateTime DateTaken { get; set; }

        public int Score { get; set; }
    }
}

Notice how it grabs the scores, and stores them in a list for later use? That's far preferable to using a DataTable.

  • Related