使用 OleDbAdaptor 和查询参数打开 Excel sheet

Open Excel sheet with OleDbAdaptor and query parameters

这是我之前打开excelsheet的方法:

public static System.Data.DataTable GetEntireSheet(string fileName,
    string sheetName)
{
    string connectionString = GetConnectionString(fileName);
    System.Data.DataTable excelTable = new System.Data.DataTable();
    excelTable.Locale = CultureInfo.InvariantCulture;

    using (OleDbConnection connection =
        new OleDbConnection(connectionString))
    {
        using (OleDbDataAdapter adaptor = new OleDbDataAdapter(
            string.Format(CultureInfo.InvariantCulture,
                "Select * from [{0}$]", sheetName),
            connection))
        {
            adaptor.Fill(excelTable);
        }
    }

    return excelTable;
}

这工作正常,但它也会生成代码分析警告:

CA2100 The query string passed to 'OleDbDataAdapter.OleDbDataAdapter(string, OleDbConnection)' in 'ExcelWrapper.GetEntireSheet(string, string)' could contain the following variables 'string.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}$]", sheetName)'. If any of these variables could come from user input, consider using a stored procedure or a parameterized SQL query instead of building the query with string concatenations.

sheet名称不是来自用户输入,所以我可以抑制警告,但抑制警告是我尽量避免的做法。

我尝试用以下方法更新方法:

string query = "SELECT * FROM [?]";
string parameter = string.Format(
    CultureInfo.InvariantCulture, "{0}$", sheetName);
using (OleDbCommand command =
    new OleDbCommand(query, connection))
{
    command.Parameters.Add("?", OleDbType.BSTR).Value =
        parameter;

    using (OleDbDataAdapter adaptor =
        new OleDbDataAdapter(command))
    {
        adaptor.Fill(excelTable);
    }
}

虽然它看起来很可疑,但它还会生成一个 OleDbException:

The Microsoft Access database engine could not find the object '?'. Make sure the object exists and that you spell its name and the path name correctly. If '?' is not a local object, check your network connection or contact the server administrator.

使用查询参数调用它的正确方法是什么?

您不能使用参数来表示 table 名称(sheet 名称)。仅当您想为 INSERT、UPDATE 和 WHERE 子句传递 VALUES 时才使用参数。

但是,正如所指出的,通过您的代码分析工具,您可以使用 table 名称的白名单,您的用户无需键入任何内容即可从中选择。

您使用 OleDbConnection 中的 GetOleDbSchemaTable 并使用 DropDownList

的 DropDownStyle 填充组合
using(OleDbConnection excel_con = new OleDbConnection(connectionString))
using(OleDbCommand cmd = new OleDbCommand())
{
    excel_con.Open();
    DataTable result = excel_con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    var names = result.AsEnumerable().Select(x => x.Field<string>("TABLE_NAME").TrimEnd('$')).ToList();
    comboBoxTables.DataSource = names;
}

现在您的代码可以使用 comboBoxTables 中的 SelectedItem 并使用字符串连接方法而不会出现 Sql 注入问题。

使用下面给出的代码,用户显式提供程序声明。

public System.Data.DataTable ReadExcel(string fileName, string fileExt, strig SheetName)
    {
        string conn = string.Empty;
        System.Data.DataTable dtexcel = new System.Data.DataTable();
        if (fileExt.CompareTo(".xls") == 0)
            conn = @"provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + ";Extended Properties='Excel 8.0;HRD=Yes;IMEX=1';"; //for below excel 2007  
        else
            conn = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties='Excel 12.0;HDR=YES';"; //for above excel 2007  
        using (OleDbConnection con = new OleDbConnection(conn))
        {
            try
            {
     String Query = String.Format("select * from [{0}]",SheetName);         
       // [sheet1] = [YouerSheetNameinExcelFile]
                //OleDbDataAdapter oleAdpt = new OleDbDataAdapter("select * from [sheet1]", con); //here we read data from sheet1  
                OleDbDataAdapter oleAdpt = new OleDbDataAdapter(Query, con); //here we read data from sheet1 and from specific cell range.   
                oleAdpt.Fill(dtexcel); //fill excel data into dataTable  
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }
        return dtexcel;
    }