问题描述
以下脚本在存储过程的sql Server 2014 Management Studio中工作,但当我通过C#应用程序.NET Framework 4.8调用存储的proc时,此脚本无法工作。 sql代码:
create proc getData
as
Insert INTO tmpLeaveImport ([CarName],Year,Make,Model)
SELECT * FROM OPENROWSET('Microsoft.ACE.OLEDB.15.0','Excel 12.0;Database=E:\Cars\Cars.xlsx','SELECT * FROM [Car Report$]')
从C#中出现以下错误:
System.Data.sqlClient.sqlException:'无法初始化数据源 链接服务器的OLE DB提供程序“ Microsoft.ACE.OLEDB.15.0”的对象 “(空值)”。链接服务器的OLE DB提供程序“ Microsoft.ACE.OLEDB.15.0” “(空)”返回消息“未指定错误”。'
在C#中执行此代码时:
//Tried the conn strign with Integrated Security=yes and sspI
string ConnString = @"Data Sournce=MysqLServerDB;Initial Catalog=dbname;Integrated Security=true;";
using (sqlConnection conn = new sqlConnection(ConnString))
{
using (sqlCommand cmd = conn.CreateCommand())
{
conn.open();
cmd.CommandText = "getData";
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
conn.open();
}
解决方法
简短版本
根据this possibly duplicate question,Excel文件可能已打开。否则这可能是一个更严重的错误。
不要使用OPENROWSET将Excel数据导入SQL Server。使用类似ExcelDataReader的库而不使用Access Engine进行读取,然后使用SqlBulkCopy将其插入目标表。您会避免很多痛苦。
using (var stream = File.Open(filePath,FileMode.Open,FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
using (var bcp = new SqlBulkCopy(connString))
{
bcp.DestinationTableName ="SomeTable";
bcp.WriteToServer(reader);
}
}
}
长版
在两种情况下,存储过程都在SQL Server而不是客户端上运行。就SQL Server而言,SSMS只是另一个客户端。假设在两种情况下都使用同一服务器,则不同之处在于,执行存储过程的帐户在每种情况下都是不同的。
使用SSMS,通常是开发者的帐户在服务器上具有sysadmin
特权。使用C#,该帐户可以是最终用户的帐户,也可以是运行具有非常受限特权的网站的应用程序池帐户。 SQL Server的默认服务帐户也是受限制的帐户。
这很重要,因为访问引擎是COM组件。要使用它,应用程序需要在注册表中查找它,这需要它自己的权限。如果在SO中搜索错误,则会发现questions where the choice of service account对是否可以使用Access Engine产生了影响。在其他情况下,文件是打开的。
另一个潜在的问题是ACE必须以与计算机上安装的任何以前的Office组件相同的体系结构为目标。如果您有x86 Office应用程序,则只能安装x86版本的ACE。那是因为您不能使用针对另一种体系结构的过程中为一种体系结构创建的COM组件。
这也意味着您不能在SQL Server的x64安装中使用x86 ACE,这是过去10多年中最常见的安装选项。