2016-11-16 58 views
2

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<SqlCommand>(); 
     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是否打開自己的連接?也許這就是爲什麼它沒有看到本地臨時表?

+0

您是否在SqlCommand命令= CreateSqlCommand(sprocName)'上添加了一個到SqlCommand的連接? – Zippy

+0

@Zippy謝謝。我錯過了那條線,我的確添加了它 –

+0

輕微彎路。你真的應該像使用你的兩個命令一樣在USING語句中包裝你的連接。 –

回答

1

如果您的SqlConnection已經打開,那麼SqlDataAdapter應該按原樣使用它(即不關閉/打開它)。

爲什麼您的存儲過程無法看到臨時表,一種可能性是ADO.NET通過調用sp_executesql來執行您的第一個SqlCommand(用於創建臨時表)。這意味着臨時表將在存儲過程sp_executesql的範圍內創建,即使您使用相同的連接,後續命令也不會看到該表。要檢查,你可以運行一個Sql Profiler跟蹤 - 如果你看到sp_executesql被用於你的第一個SqlCommand,那麼你會遇到問題。

在此註釋: Sql Server temporary table disappears可能是相關的:

老實說,我認爲它與SqlCommand的文字是 結構化的方式做。如果它是一個簡單的select into,沒有參數,那麼它可以作爲一個簡單的select語句運行,所以它不會被包裝在像'sp_executesql'這樣的 SqlProcedure中,所以它將在後續查詢中保持可見狀態,使用它相同的SqlCommand和SqlConnection 對象。另一方面,如果它是一個複雜的語句,臨時表 可能會在'sp_executesql'之類的存儲過程中創建,並且 將在命令完成時超出範圍。 - Triynko 2月25日在'15 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')將永遠是空的(除非你已經在臨時數據庫) 。

編輯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 

最後,它會顯示:「完成,NUM行1「

+0

非常感謝您提供寶貴的信息。我從來不知道這是如何工作的。爲了回答你的問題,在跟蹤中沒有sp_executesql,此外,包括臨時表創建命令的命令的clientprocessid和spid都是一樣的,那麼我們可以假設「範圍」是相同的嗎? –

+0

@MeggieLuski - 是的,如果你沒有看到sp_executesql被使用,我希望存儲的proc *應該*能夠看到臨時表。它還沒有工作嗎? –

+0

它的工作! –

2

從上SqlDataAdapter.Fill()方法的文檔:

與SELECT命令相關的IDbConnection對象必須是有效的,但它並不需要開放。如果在調用Fill之前關閉了IDbConnection,則會打開它以檢索數據,然後關閉。如果連接在調用Fill之前打開,則它保持打開狀態。

所以我們在這裏看到的是SqlDataAdapter的不使用任何特殊的專用連接,但會嘗試自動打開你給它的任何連接。

您在這裏遇到的問題是每個撥打.Fill()方法的電話都發生在單獨的Execution Context

+0

非常感謝。在這種情況下,我如何強制它發生在相同的執行上下文中? –

+0

您可以嘗試一個Transaction屬性,但您可能需要使用幾個命令將所有這些構建到一個大的sql字符串中。你也可以嘗試一個全局臨時表('## CRM2Oxa_ID_MAPPING'而不是'#CRM2Oxa_ID_MAPPING'),但這可能會有它自己的問題。 –

+0

你將如何從命令建立一個sql字符串? –