SqlDataAdapter apre la propria connessione?

SqlDataAdapter apre la propria connessione?

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; } 

Ricevo un messaggio dal database che la tabella #temptable non esiste.

SqlDataAdapter apre la propria connessione? Forse è questo il motivo per cui non vede la tabella temporanea locale?

Se SqlConnection era già aperto, SqlDataAdapter dovrebbe usarlo così com’è (cioè senza chiuderlo / aprirlo).

Una possibilità sul motivo per cui i processi memorizzati non possono vedere la tabella temporanea, è che ADO.NET ha eseguito il primo SqlCommand (utilizzato per creare la tabella temporanea), con una chiamata sp_executesql. Ciò significherebbe che la tabella temporanea viene creata nell’ambito dello stored proc sp_executesql e non sarebbe visibile ai comandi successivi, anche se si sta utilizzando la stessa connessione. Per verificare, è ansible eseguire una traccia Sql Profiler: se si vede sp_executesql utilizzato per il primo SqlCommand, si verificherà un problema.

Questo commento su: La tabella temporanea di Sql Server scompare potrebbe essere rilevante:

Onestamente penso che abbia a che fare con il modo in cui è strutturato il testo SqlCommand. Se si tratta di una semplice selezione in, senza parametri, allora può essere eseguito come una semplice istruzione select, quindi non verrà racchiuso in una procedura Sql come “sp_executesql”, quindi rimarrà visibile alle query successive che utilizzano lo stesso SqlCommand e Oggetto SqlConnection. D’altra parte, se si tratta di un’istruzione complessa, la tabella temporanea può essere creata all’interno di una stored procedure come “sp_executesql” e uscirà dall’ambito al termine del comando. – Triynko, 25 febbraio 15 alle 21:10

Se ADO.NET utilizza effettivamente sp_executesql per il comando di creazione tabella, potrebbe essere ansible convincerlo a non utilizzarlo, suddividendo il comando in 2 SqlCommands: uno per rilasciare la tabella temporanea se esiste, e un’altra per solo crea la tabella temporanea.

EDIT : su una nota a margine, questo codice:

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

dovrebbe probabilmente essere:

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

altrimenti OBJECT_ID('#CRM2Oxa_ID_MAPPING') sarà sempre nullo (a meno che tu non sia già nel database temporaneo).

EDIT 2 : ecco un semplice codice che funziona per me:

  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); 

Il proc memorizzato si presenta così:

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

Alla fine, visualizza: “done, num rows 1”

Dalla documentazione sul metodo SqlDataAdapter.Fill() :

L’object IDbConnection associato al comando select deve essere valido, ma non deve essere aperto. Se IDbConnection viene chiuso prima che Fill venga chiamato, viene aperto per recuperare i dati e quindi chiuso. Se la connessione è aperta prima che Fill venga chiamata, rimane aperta.

Quindi vediamo qui che SqlDataAdapter non usa alcuna connessione privata speciale, ma proverà ad aprire automaticamente qualsiasi connessione tu gli dai.

Il problema che si verifica qui è che ogni chiamata al metodo .Fill() verifica in un contesto di esecuzione separato .