2010-06-04 13 views
22

Ho una classe denominata Entry dichiarata in questo modo:Come devo inserire più record multipli?

class Entry{ 
    string Id {get;set;} 
    string Name {get;set;} 
} 

e poi un metodo che accetterà più questi Entry oggetti per l'inserimento nel database utilizzando ADO.NET:

static void InsertEntries(IEnumerable<Entry> entries){ 
    //build a SqlCommand object 
    using(SqlCommand cmd = new SqlCommand()){ 
     ... 
     const string refcmdText = "INSERT INTO Entries (id, name) VALUES (@id{0},@name{0});"; 
     int count = 0; 
     string query = string.Empty; 
     //build a large query 
     foreach(var entry in entries){ 
      query += string.Format(refcmdText, count); 
      cmd.Parameters.AddWithValue(string.Format("@id{0}",count), entry.Id); 
      cmd.Parameters.AddWithValue(string.Format("@name{0}",count), entry.Name); 
      count++; 
     } 
     cmd.CommandText=query; 
     //and then execute the command 
     ... 
    } 
} 

E la mia domanda è questo: dovrei continuare a utilizzare il modo sopra riportato di inviare più istruzioni di inserimento (creare una stringa gigante di istruzioni di inserimento e i relativi parametri e inviarlo tramite la rete), o dovrei mantenere una connessione aperta e inviare una singola istruzione di inserimento per ogni Entry piace this:

using(SqlCommand cmd = new SqlCommand(){ 
    using(SqlConnection conn = new SqlConnection(){ 
     //assign connection string and open connection 
     ... 
     cmd.Connection = conn; 
     foreach(var entry in entries){ 
      cmd.CommandText= "INSERT INTO Entries (id, name) VALUES (@id,@name);"; 
      cmd.Parameters.AddWithValue("@id", entry.Id); 
      cmd.Parameters.AddWithValue("@name", entry.Name); 
      cmd.ExecuteNonQuery(); 
     } 
    } 
} 

Cosa ne pensi? Ci sarà una differenza di prestazioni nel server Sql tra i due? Ci sono altre conseguenze di cui dovrei essere a conoscenza?

+0

Grazie per tutti i vostri suggerimenti! Prenderò la risposta di @ Giorgi perché più o meno risponde alla domanda originale – bottlenecked

+0

puoi usare il tipo definito dall'utente nel server SQl per passare DataTable al server SQL http://www.fourthbottle.com/2014/09/how- to-insert-multiple-records-into.html – Venki

risposta

20

Se fossi in te non sarebbe utilizzare uno dei loro.

Lo svantaggio del primo è che i nomi dei parametri potrebbero scontrarsi se ci sono gli stessi valori nella lista.

Lo svantaggio del secondo è che si stanno creando comandi e parametri per ciascuna entità.

Il modo migliore è di avere il comando testo e i parametri costruiti una volta (utilizzare Parameters.Add per aggiungere i parametri) modificare i loro valori nel ciclo ed eseguire il comando. In questo modo la dichiarazione verrà preparata una sola volta. Dovresti anche aprire la connessione prima di avviare il loop e chiuderlo dopo di esso.

+6

'SQLCommand' è ottimizzato per il processo descritto da Giorgi. La connessione sottostante verrà mantenuta come sottolinea Tim. Vorrei anche usare un 'Transaction' raccomandato da Tim. – AMissico

+0

così, anche 'cmd.ExecuteNonQuery();' dovrebbe essere all'interno del ciclo? – Ciccio

+1

@Giorgi Cosa fare quando il numero di parametri può superare il limite di 2100? –

8

Si dovrebbe eseguire il comando su ogni anello invece di costruire un comando enorme di testo (a proposito, StringBuilder è fatto per questo) La connessione sottostante non si chiuderà e riaprirà per ogni ciclo, lasciare che il collegamento Pool Manager gestire questo . Date un'occhiata a questo link per ulteriori informazioni: Tuning Up ADO.NET Connection Pooling in ASP.NET Applications

Se si vuole garantire che ogni comando viene eseguito correttamente è possibile utilizzare un rollback Transaction e, se necessario,

+0

O meglio usare Linq2Sql e lasciare che sia gestito da Linq2Sql. – Amitabh

+2

'SQLCommand' è ottimizzato per il processo descritto da Giorgi. La connessione sottostante verrà mantenuta come sottolinea Tim. Vorrei anche usare un 'Transaction' raccomandato da Tim. – AMissico

39
static void InsertSettings(IEnumerable<Entry> settings) { 
    using (SqlConnection oConnection = new SqlConnection("Data Source=(local);Initial Catalog=Wip;Integrated Security=True")) { 
     oConnection.Open(); 
     using (SqlTransaction oTransaction = oConnection.BeginTransaction()) { 
      using (SqlCommand oCommand = oConnection.CreateCommand()) { 
       oCommand.Transaction = oTransaction; 
       oCommand.CommandType = CommandType.Text; 
       oCommand.CommandText = "INSERT INTO [Setting] ([Key], [Value]) VALUES (@key, @value);"; 
       oCommand.Parameters.Add(new SqlParameter("@key", SqlDbType.NChar)); 
       oCommand.Parameters.Add(new SqlParameter("@value", SqlDbType.NChar)); 
       try { 
        foreach (var oSetting in settings) { 
         oCommand.Parameters[0].Value = oSetting.Key; 
         oCommand.Parameters[1].Value = oSetting.Value; 
         if (oCommand.ExecuteNonQuery() != 1) { 
          //'handled as needed, 
          //' but this snippet will throw an exception to force a rollback 
          throw new InvalidProgramException(); 
         } 
        } 
        oTransaction.Commit(); 
       } catch (Exception) { 
        oTransaction.Rollback(); 
        throw; 
       } 
      } 
     } 
    } 
} 
2

quando sono un sacco di voci in considerazione di utilizzare SqlBulkCopy

-1

stored procedure per inserire record multipli usando singola inserzione:

ALTER PROCEDURE [dbo].[Ins] 
@i varchar(50), 
@n varchar(50), 
@a varchar(50), 
@i1 varchar(50), 
@n1 varchar(50), 
@a1 varchar(50), 
@i2 varchar(50), 
@n2 varchar(50), 
@a2 varchar(50) 
AS 
INSERT INTO t1 
SELECT  @i AS Expr1, @i1 AS Expr2, @i2 AS Expr3 
UNION ALL 
SELECT  @n AS Expr1, @n1 AS Expr2, @n2 AS Expr3 
UNION ALL 
SELECT  @a AS Expr1, @a1 AS Expr2, @a2 AS Expr3 
RETURN 

codice dietro:

protected void Button1_Click(object sender, EventArgs e) 
{ 
    cn.Open(); 
    SqlCommand cmd = new SqlCommand("Ins",cn); 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.Parameters.AddWithValue("@i",TextBox1.Text); 
    cmd.Parameters.AddWithValue("@n",TextBox2.Text); 
    cmd.Parameters.AddWithValue("@a",TextBox3.Text); 
    cmd.Parameters.AddWithValue("@i1",TextBox4.Text); 
    cmd.Parameters.AddWithValue("@n1",TextBox5.Text); 
    cmd.Parameters.AddWithValue("@a1",TextBox6.Text); 
    cmd.Parameters.AddWithValue("@i2",TextBox7.Text); 
    cmd.Parameters.AddWithValue("@n2",TextBox8.Text); 
    cmd.Parameters.AddWithValue("@a2",TextBox9.Text); 
    cmd.ExecuteNonQuery(); 
    cn.Close(); 
    Response.Write("inserted"); 
    clear(); 
} 
+6

Cosa succede se ho 2 milioni di voci? –

-4
ClsConectaBanco bd = new ClsConectaBanco(); 

StringBuilder sb = new StringBuilder(); 
sb.Append(" INSERT INTO FAT_BALANCETE "); 
sb.Append(" ([DT_LANCAMENTO]   "); 
sb.Append(" ,[ID_LANCAMENTO_CONTABIL] "); 
sb.Append(" ,[NR_DOC_CONTABIL]   "); 
sb.Append(" ,[TP_LANCAMENTO_GERADO] "); 
sb.Append(" ,[VL_LANCAMENTO]   "); 
sb.Append(" ,[TP_NATUREZA]    "); 
sb.Append(" ,[CD_EMPRESA]    "); 
sb.Append(" ,[CD_FILIAL]    "); 
sb.Append(" ,[CD_CONTA_CONTABIL]  "); 
sb.Append(" ,[DS_CONTA_CONTABIL]  "); 
sb.Append(" ,[ID_CONTA_CONTABIL]  "); 
sb.Append(" ,[DS_TRIMESTRE]   "); 
sb.Append(" ,[DS_SEMESTRE]    "); 
sb.Append(" ,[NR_TRIMESTRE]   "); 
sb.Append(" ,[NR_SEMESTRE]    "); 
sb.Append(" ,[NR_ANO]     "); 
sb.Append(" ,[NR_MES]     "); 
sb.Append(" ,[NM_FILIAL])    "); 
sb.Append(" VALUES      "); 
sb.Append(" (@DT_LANCAMENTO   "); 
sb.Append(" ,@ID_LANCAMENTO_CONTABIL "); 
sb.Append(" ,@NR_DOC_CONTABIL   "); 
sb.Append(" ,@TP_LANCAMENTO_GERADO  "); 
sb.Append(" ,@VL_LANCAMENTO   "); 
sb.Append(" ,@TP_NATUREZA    "); 
sb.Append(" ,@CD_EMPRESA    "); 
sb.Append(" ,@CD_FILIAL    "); 
sb.Append(" ,@CD_CONTA_CONTABIL  "); 
sb.Append(" ,@DS_CONTA_CONTABIL  "); 
sb.Append(" ,@ID_CONTA_CONTABIL  "); 
sb.Append(" ,@DS_TRIMESTRE    "); 
sb.Append(" ,@DS_SEMESTRE    "); 
sb.Append(" ,@NR_TRIMESTRE    "); 
sb.Append(" ,@NR_SEMESTRE    "); 
sb.Append(" ,@NR_ANO     "); 
sb.Append(" ,@NR_MES     "); 
sb.Append(" ,@NM_FILIAL)    "); 

SqlCommand cmd = new SqlCommand(sb.ToString(), bd.CriaConexaoSQL()); 
bd.AbrirConexao(); 

cmd.Parameters.Add("@DT_LANCAMENTO", SqlDbType.Date); 
cmd.Parameters.Add("@ID_LANCAMENTO_CONTABIL", SqlDbType.Int); 
cmd.Parameters.Add("@NR_DOC_CONTABIL", SqlDbType.VarChar,255); 
cmd.Parameters.Add("@TP_LANCAMENTO_GERADO", SqlDbType.VarChar,255); 
cmd.Parameters.Add("@VL_LANCAMENTO", SqlDbType.Decimal); 
cmd.Parameters["@VL_LANCAMENTO"].Precision = 15; 
cmd.Parameters["@VL_LANCAMENTO"].Scale = 2; 
cmd.Parameters.Add("@TP_NATUREZA", SqlDbType.VarChar, 1); 
cmd.Parameters.Add("@CD_EMPRESA",SqlDbType.Int); 
cmd.Parameters.Add("@CD_FILIAL", SqlDbType.Int); 
cmd.Parameters.Add("@CD_CONTA_CONTABIL", SqlDbType.VarChar, 255); 
cmd.Parameters.Add("@DS_CONTA_CONTABIL", SqlDbType.VarChar, 255); 
cmd.Parameters.Add("@ID_CONTA_CONTABIL", SqlDbType.VarChar,50); 
cmd.Parameters.Add("@DS_TRIMESTRE", SqlDbType.VarChar, 4); 
cmd.Parameters.Add("@DS_SEMESTRE", SqlDbType.VarChar, 4); 
cmd.Parameters.Add("@NR_TRIMESTRE", SqlDbType.Int); 
cmd.Parameters.Add("@NR_SEMESTRE", SqlDbType.Int); 
cmd.Parameters.Add("@NR_ANO", SqlDbType.Int); 
cmd.Parameters.Add("@NR_MES", SqlDbType.Int); 
cmd.Parameters.Add("@NM_FILIAL", SqlDbType.VarChar, 255); 
cmd.Prepare(); 

foreach (dtoVisaoBenner obj in lista) 
{ 
    cmd.Parameters["@DT_LANCAMENTO"].Value = obj.CTLDATA; 
    cmd.Parameters["@ID_LANCAMENTO_CONTABIL"].Value = obj.CTLHANDLE.ToString(); 
    cmd.Parameters["@NR_DOC_CONTABIL"].Value = obj.CTLDOCTO.ToString(); 
    cmd.Parameters["@TP_LANCAMENTO_GERADO"].Value = obj.LANCAMENTOGERADO; 
    cmd.Parameters["@VL_LANCAMENTO"].Value = obj.CTLANVALORF; 
    cmd.Parameters["@TP_NATUREZA"].Value = obj.NATUREZA; 
    cmd.Parameters["@CD_EMPRESA"].Value = obj.EMPRESA; 
    cmd.Parameters["@CD_FILIAL"].Value = obj.FILIAL; 
    cmd.Parameters["@CD_CONTA_CONTABIL"].Value = obj.CONTAHANDLE.ToString(); 
    cmd.Parameters["@DS_CONTA_CONTABIL"].Value = obj.CONTANOME.ToString(); 
    cmd.Parameters["@ID_CONTA_CONTABIL"].Value = obj.CONTA; 
    cmd.Parameters["@DS_TRIMESTRE"].Value = obj.TRIMESTRE; 
    cmd.Parameters["@DS_SEMESTRE"].Value = obj.SEMESTRE; 
    cmd.Parameters["@NR_TRIMESTRE"].Value = obj.NRTRIMESTRE; 
    cmd.Parameters["@NR_SEMESTRE"].Value = obj.NRSEMESTRE; 
    cmd.Parameters["@NR_ANO"].Value = obj.NRANO; 
    cmd.Parameters["@NR_MES"].Value = obj.NRMES; 
    cmd.Parameters["@NM_FILIAL"].Value = obj.NOME; 
    cmd.ExecuteNonQuery(); 
    rowAffected++; 
} 
+2

si prega di non rispondere solo con il codice. – Cybermaxs

+13

Questa è un'opera d'arte. – Ashe

+0

Picasso sarebbe orgoglioso – Monkey

0

È possibile inserire direttamente un DataTable se è stato creato correttamente.

Prima di tutto assicurarsi che le colonne della tabella di accesso abbiano gli stessi nomi di colonna e tipi simili. Quindi puoi usare questa funzione che credo sia molto veloce ed elegante.

public void AccessBulkCopy(DataTable table) 
{ 
    foreach (DataRow r in table.Rows) 
     r.SetAdded(); 

    var myAdapter = new OleDbDataAdapter("SELECT * FROM " + table.TableName, _myAccessConn); 

    var cbr = new OleDbCommandBuilder(myAdapter); 
    cbr.QuotePrefix = "["; 
    cbr.QuoteSuffix = "]"; 
    cbr.GetInsertCommand(true); 

    myAdapter.Update(table); 
} 
0

In seguito @ Tim Mahy - Ci sono due modi possibili per alimentare SqlBulkCopy: un DataReader o tramite DataTable.Qui il codice per DataTable:

DataTable dt = new DataTable(); 
dt.Columns.Add(new DataColumn("Id", typeof(string))); 
dt.Columns.Add(new DataColumn("Name", typeof(string))); 
foreach (Entry entry in entries) 
    dt.Rows.Add(new string[] { entry.Id, entry.Name }); 

using (SqlBulkCopy bc = new SqlBulkCopy(connection)) 
{ // the following 3 lines might not be neccessary 
    bc.DestinationTableName = "Entries"; 
    bc.ColumnMappings.Add("Id", "Id"); 
    bc.ColumnMappings.Add("Name", "Name"); 

    bc.WriteToServer(dt); 
} 
Problemi correlati