SqlDataAdapter是否打开自己的连接?

SqlDataAdapter是否打开自己的连接?

private DataTable UpdateOxa(ProductCatalogSyncData syncDataModel, string connectionString) { var ds = syncDataModel.SyncDataSet; var dtResults = new DataTable("BillingIds"); var syncConfig = syncDataModel.XDataMapping; string EntityName; string queryString = @" IF OBJECT_ID('#CRM2Oxa_ID_MAPPING') IS NOT NULL DROP TABLE #CRM2Oxa_ID_MAPPING CREATE TABLE #CRM2Oxa_ID_MAPPING( [EntityName][nvarchar](1000) NULL, [TableName][nvarchar](1000) NULL, [CRMID][uniqueidentifier] NULL, [OxaID][int] NOT NULL, [CRMColumnName][nvarchar](1000) NULL ) "; var listOfSqlCommands = new List(); var OxaConnection = new SqlConnection(connectionString); try { OxaConnection.Open(); using (var createTempTableCommand = new SqlCommand(queryString, OxaConnection)) { createTempTableCommand.ExecuteNonQuery(); } foreach (DataTable dt in ds.Tables) { EntityName = StringDefaultIfNull( syncConfig.Root.XPathSelectElement("./entity[@name='" + dt.TableName + "']"), "OxaTableName").Substring(3); var OxaCommand = new SqlCommand(); OxaCommand.CommandType = CommandType.StoredProcedure; OxaCommand.CommandText = "Oxa720_P_" + EntityName + "Sync"; var entityNameParam = new SqlParameter("@EntityName", dt.TableName); OxaCommand.Parameters.Clear(); OxaCommand.Parameters.Add(entityNameParam); var tblParam = new SqlParameter("@O720_" + EntityName, SqlDbType.Structured); tblParam.Value = dt; OxaCommand.Parameters.Add(tblParam); OxaCommand.Connection = OxaConnection; listOfSqlCommands.Add(OxaCommand); } foreach (var command in listOfSqlCommands) { using (var da = new SqlDataAdapter(command)) { da.Fill(dtResults); } } } finally { OxaConnection.Close(); } return dtResults; } 

我从数据库中收到一条消息,表示#temptable表不存在。

SqlDataAdapter是否打开自己的连接? 也许这就是为什么它没有看到当地的临时表?

如果您的SqlConnection已经打开,那么SqlDataAdapter应该按原样使用它(即不关闭/打开它)。

关于为什么存储过程无法看到临时表的一种可能性是,ADO.NET执行了第一个SqlCommand(用于创建临时表),并使用sp_executesql调用。 这意味着临时表在存储的proc sp_executesql的范围内创建,即使您使用相同的连接也不会对后续命令可见。 要检查,您可以运行Sql Profiler跟踪 – 如果您看到sp_executesql用于您的第一个SqlCommand,那么您将遇到问题。

此评论在: Sql Server临时表消失可能是相关的:

老实说,我认为它与SqlCommand文本的结构方式有关。 如果它是一个简单的select into,没有参数,那么它可以作为一个简单的select语句运行,因此它不会被包装在像’sp_executesql’这样的SqlProcedure中,所以它对于使用相同SqlCommand的后续查询仍然是可见的SqlConnection对象。 另一方面,如果它是一个复杂的语句,临时表可能会在“sp_executesql”之类的存储过程中创建,并且在命令完成时将超出范围。 – Triynko 2015年2月25日21:10

如果ADO.NET确实使用sp_executesql作为表创建命令,那么你可以通过将命令分解为2个SqlCommands来诱使它不使用它:一个用于删除临时表(如果存在),另一个用于删除创建临时表。

编辑 :在旁注,这段代码:

 IF OBJECT_ID('#CRM2Oxa_ID_MAPPING') IS NOT NULL DROP TABLE #CRM2Oxa_ID_MAPPING 

应该是:

 IF OBJECT_ID('tempdb..#CRM2Oxa_ID_MAPPING') IS NOT NULL DROP TABLE #CRM2Oxa_ID_MAPPING 

否则OBJECT_ID('#CRM2Oxa_ID_MAPPING')将始终为null(除非您已经在临时数据库中)。

编辑2 :这里有一些适合我的简单代码:

  DataSet ds = new DataSet(); using(SqlConnection conn = new SqlConnection("YourConnectionString")) { conn.Open(); string str = "if object_id('tempdb..#mytest') is not null drop table #mytest; create table #mytest (id int)"; // create temp table using(SqlCommand cmdc = new SqlCommand(str, conn)) { cmdc.ExecuteNonQuery(); } // insert row using (SqlCommand cmdi = new SqlCommand("insert #mytest (id) values (1)", conn)) { cmdi.ExecuteNonQuery(); } // use it using (SqlCommand cmds = new SqlCommand("dbo.mytestproc", conn)) { cmds.CommandType = CommandType.StoredProcedure; cmds.Parameters.Add("@id", SqlDbType.Int).Value = 1; cmds.Connection = conn; using (SqlDataAdapter da = new SqlDataAdapter(cmds)) { da.Fill(ds); } } // clean up - drop temp table string strd = "if object_id('tempdb..#mytest') is not null drop table #mytest"; using (SqlCommand cmdd = new SqlCommand(strd, conn)) { cmdd.ExecuteNonQuery(); } } MessageBox.Show("done, num rows " + ds.Tables[0].Rows.Count); 

存储过程如下所示:

 create proc dbo.mytestproc(@id int) as select * from #mytest where id = @id GO 

最后,它显示:“done,num rows 1”

SqlDataAdapter.Fill()方法的文档:

与select命令关联的IDbConnection对象必须有效,但不需要打开它。 如果在调用Fill之前关闭了IDbConnection ,则会打开它以检索数据然后关闭。 如果在调用Fill之前连接已打开,则它将保持打开状态。

所以我们在这里看到SqlDataAdapter不使用任何特殊的私有连接,但会尝试自动打开你给它的任何连接。

你在这里遇到的问题是每次调用.Fill()方法都是在一个单独的执行环境中进行的