Search code examples
c#sql-serverasp.net-coreexceldatareader

I get a "Specified method is not supported" error when i try to use ExcelDataReader to upload file to database


I've written a method, BulkCopy, to upload my Excel file to SQL Server database table. I am trying to unit test this and it fails each time with "System.NotSupportedException : Specified method is not supported".

If someone could have a look it would be much appreciated.

Kind regards,

Emmett

    public static void BulkCopy(string inputFilePath, string tableName)
    {

        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
        var stream = File.Open(inputFilePath, FileMode.Open, FileAccess.Read);
        using (var reader = ExcelReaderFactory.CreateReader(stream))
        {
            using (var bulkCopy = new SqlBulkCopy(ConnectionString))
            {

                bulkCopy.EnableStreaming = true;
                bulkCopy.DestinationTableName = tableName;
                reader.Read();
                var cols = Enumerable.Range(0, reader.FieldCount).Select(i => reader.GetValue(i)).ToArray();
                foreach (var col in cols)
                {
                    var column = cols.GetValue(0).ToString();

                    if (column.Trim() == "Column 1")
                    {
                        bulkCopy.ColumnMappings.Add(column, "Column 1");
                    }

                    if (column.Trim() == "Column 2")
                    {
                        bulkCopy.ColumnMappings.Add(column, "Column 2");
                    }

                    if (column.Trim() == "Column 3")
                    {
                        bulkCopy.ColumnMappings.Add(column, "Column 3");
                    }

                //continued for column mappings...

                }

                bulkCopy.WriteToServer(reader);
            }
            Console.WriteLine("Copy data to database done (DataReader).");
        }
    }

Solution

  • I tested your code ,the issue is showed in the following code ,you reader is incorrect.

    bulkCopy.WriteToServer(reader);
    

    Pass the datatable into bulk , try the below code

    public static void BulkCopy(string inputFilePath, string tableName)
        {
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
            var stream = System.IO.File.Open(inputFilePath, FileMode.Open, FileAccess.Read);
            IExcelDataReader reader;
    
            if (inputFilePath.EndsWith(".xls"))
                reader = ExcelReaderFactory.CreateBinaryReader(stream);
            else if (inputFilePath.EndsWith(".xlsx"))
                reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
            else
                throw new Exception("The file to be processed is not an Excel file");
            var conf = new ExcelDataSetConfiguration
            {
                ConfigureDataTable = _ => new ExcelDataTableConfiguration
                {
                    UseHeaderRow = true
                }
            };
            var dataSet = reader.AsDataSet(conf);
    
            // Now you can get data from each sheet by its index or its "name"
            var dataTable = dataSet.Tables[0];
    
            using (var bulkCopy = new SqlBulkCopy(ConnectionString))
                {
                    bulkCopy.EnableStreaming = true;
                    bulkCopy.DestinationTableName = tableName;
                    reader.Read();
                    var cols = Enumerable.Range(0, reader.FieldCount).Select(i => reader.GetValue(i)).ToArray();
                    foreach (var col in cols)
                    {
                        var column =col.ToString();
    
                        if (column.Trim() == "Column 1")
                        {
                            bulkCopy.ColumnMappings.Add(column, "Column1");
                        }
    
                        if (column.Trim() == "Column 2")
                        {
                            bulkCopy.ColumnMappings.Add(column, "Column2");
                        }
    
                        if (column.Trim() == "Column 3")
                        {
                            bulkCopy.ColumnMappings.Add(column, "Column3");
                        }
    
                        //continued for column mappings...
    
                    }
                    bulkCopy.WriteToServer(dataTable);
                }
                Console.WriteLine("Copy data to database done (DataReader).");           
        }
    

    Pass the dataReader into bulk, change your foreach part as shown

                   for (var i = 0; i<cols.Count();i++)
                    {
                        if (cols[i].ToString().Trim() == "Column 1")
                        {
                            bulkCopy.ColumnMappings.Add(i, "Column1");
                        }
    
                        if (cols[i].ToString().Trim() == "Column 2")
                        {
                            bulkCopy.ColumnMappings.Add(i, "Column2");
                        }
    
                        if (cols[i].ToString().Trim() == "Column 3")
                        {
                            bulkCopy.ColumnMappings.Add(i, "Column3");
                        }
    
                        //continued for column mappings...
    
                    }