首页 > 解决方案 > 通过 SpreadSheetGear 将 .xlsx 读取到 dto

问题描述

我想在 .Net Core 3.1 控制台应用程序中使用电子表格将 exel 文件读取到自定义模型(映射它!)。我的 excel 文件如下所示:

| Customers | Sales Item | Sale Date  | Contact | Quantity |
| IBM       | Keyboard   | 28-10-2011 |         | 2        |
| Logitech  | Mouse      | 27-09-2011 | joe     | 5        |

DTO

public class CustomersDto
{
    public string Customers { get; set; }

    public string SalesItem { get; set; }

    public DateTime Date { get; set; }

    public string Contact  { get; set; }

    public int Quantity{ get; set; }
}

通用代码:

private static void Main(string[] args)
    {
        var workbook =
            Factory.GetWorkbook(
                @"D:\MyFiles\SellersCollections.xlsx");
        var worksheet = workbook.Worksheets[0];

        var cells = worksheet.UsedRange;
        List<CustomersDto> test = new List<CustomersDto>();
        CustomersDto dto = new CustomersDto();

        for (var i = 0; i < cells.RowCount; i++)
        {
            if (i == 1) // skip header (0)
            {
                for (var j = 0; j < cells.ColumnCount; j++)
                {
                   Console.WriteLine(cells[i,j].Value);

                   // What should I do HERE to MAP to DTO
                   // Something like:
                   // dto.Customers = cells[i, j]; ???
                }
            }
        }
        
        Console.ReadLine();
    }

有没有办法映射cells[i, j]IRange建模类?

标签: c#.net.net-coremappingspreadsheetgear

解决方案


SpreadsheetGear 中不存在任何内置映射或绑定功能来为您执行此操作,因此您需要构建自己的例程来执行此操作。如果您的工作簿和 DTO 定义明确且事先已知,我将保留外部“行循环”,但删除内部“列循环”并手动索引每个列单元格值,并根据需要将其放入相应的 DTO 属性中。当然,这意味着您的代码对每一列中包含的信息及其在 DTO 中的相应属性有一些了解。如果你需要一些更动态的东西,你必须建立一个更精细的系统,这超出了这里的回答范围。

在获取单元格值方面,IRange您可能需要查看两个主要属性:

  • 范围。- 此属性是类型object并返回单元格的“原始”值。例如 a doubleof1.23或 a booloftruestringof "abc"
  • 范围。文本- 这是类型string并返回单元格的“格式化”值 - 这意味着它采用 IRange.Value 并将该单元格的数字格式 (IRange. NumberFormat ) 应用于该值并返回结果字符串。换句话说,这将返回您从 Excel 的 UI 和/或 SpreadsheetGear 的 WorkbookView UI 控件看到的内容。因此,如果一个单元格的 IRange.Value 为双 1.23,但被格式化为显示 4 个小数位 ( IRange.NumberFormat == "0.0000"),则 IRange.Text 将返回字符串"1.2300"。假设具有 的单元格的通用 NumberFormat booltrueIRange.Text 将返回字符串"TRUE"。等等。

需要特别考虑日期。这是因为 Excel 中的日期、时间和日期时间在内部存储为序列数字双精度值,值 1.0 为 1900 年 1 月 1 日,2.0 为 1900 年 1 月 2 日,今天(2021 年 3 月 23 日)为 44278 等;该值的小数部分表示当天的时间(即,0.5 是中午,0.625 是下午 3:00)。单元格显示为“日期”或“时间”或“日期时间”的事实纯粹是应用于单元格的 IRange.NumberFormat 的函数(“m/d/yyyy”或“h:mm:ss”, ETC)。如果DateTime要从单元格中获取实际对象,则需要使用 IWorkbook。NumberToDateTime ( double serialDate ) 辅助方法来执行此操作。

所以底线,你的例程可能看起来像下面这样:

private static void Main(string[] args)
{
    var workbook =
    Factory.GetWorkbook(
        @"D:\MyFiles\SellersCollections.xlsx");
    var worksheet = workbook.Worksheets[0];

    var cells = worksheet.UsedRange;
    List<CustomersDto> dtoList = new List<CustomersDto>();

    for (var i = 0; i < cells.RowCount; i++)
    {
        if (i == 1) // skip header (0)
        {
            CustomersDto dto = new CustomersDto();

            // First two columns appear to be text, using IRange.Text should be fine
            // but could probably use IRange.Value as well.
            dto.Customers = cells[i, 0].Text;
            dto.SalesItem = cells[i, 1].Text;

            // Need to convert serial date stored in cell values to actual DateTimes.
            // Use IRange.Value and cast to double (may need to introduce some value 
            // type checking here if other values or empty cell values are allowed.  
            // See IRange.ValueType to detect what kind of value is stored in a given 
            // cell).
            double serialDate = (double)cells[i, 2].Value;
            // Convert serial date to a true DateTime object
            DateTime dateTime = workbook.NumberToDateTime(serialDate);
            dto.Date = dateTime;

            // Contact column appears to be text, so IRange.Text should suffice.
            dto.Contact = cells[i, 3].Text;

            // Appears to be a number so cast to double (see note above about possible
            // value type checking) and then cast again to int.
            dto.Quantity = (int)(double)cells[i, 4].Value;

            // Add to list
            dtoList.Add(dto);
        }
    }

    Console.ReadLine();
}

推荐阅读