2010-12-13 6 views
1

J'ai besoin de migrer des données d'un DB vers un autre. J'ai choisi d'utiliser SqlBulkCopy, mais un problème avec elle, parce que la base de données source a différente collation que la destination, donc, j'ai une exception:SqlBulkCopy avec différents classements

System.InvalidOperationException: The locale id '1049' of the source column 'Id' and the locale id '1033' of the destination column 'Id' do not match. 
    at System.Data.SqlClient.SqlBulkCopy.AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet internalResults) 
    at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternal() 
    at System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServer(Int32 columnCount) 
    at System.Data.SqlClient.SqlBulkCopy.WriteToServer(IDataReader reader) 
    at MigrateToNormalized.DirectMapCommand.Migrate(SqlConnection source, SqlConnection destination, SqlTransaction transaction) in D:\Projects\APS\DTE\MigrateTo 
Normalized\MigrateToNormalized\MigrateToNormalized\DirectMapCommand.cs:line 53 
    at MigrateToNormalized.Program.Main(String[] args) in D:\Projects\APS\DTE\MigrateToNormalized\MigrateToNormalized\MigrateToNormalized\Program.cs:line 32 

Quelqu'un peut-il me dire, comment résoudre ce problème sans directe utilisation des instructions COLLATE dans une requête SQL? Existe-t-il un moyen simple de modifier le classement pour toutes les colonnes de la base de données source?

Répondre

-1

Vous pouvez modifier les classements pour les colonnes de la table que vous utilisez pour sqlbulkcopy.

Par exemple

CREATE TABLE T3 ( C1 int PRIMARY KEY, C2 varchar (50) NULL, NULL C3 int, int C4); GO

ALTER TABLE T3 ALTER colonne C2 varchar (50) COLLATE Latin1_General_BIN

+0

C'est vrai, mais j'ai beaucoup de tables et beaucoup de colonnes. Je ne veux pas changer les colaisons pour chacun d'entre eux manuellement. –

+0

Cela ne répond pas à la question du tout. Vous ne pouvez pas modifier la base de données client pour le faire fonctionner. – billybob

2

Il est vrai que lorsque nous utilisons SqlBulkCopy, quelque temps, il donne l'erreur, la meilleure façon de cartographier les colonnes lorsque vous utilisez SqlBulkCopy .

Mon code privious:

SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder("Data Source=ServerName;User Id=userid;Password=****;Initial Catalog=Deepak; Pooling=true; Max pool size=200; Min pool size=0"); 

SqlConnection con = new SqlConnection(cb.ConnectionString); 

     SqlCommand cmd = new SqlCommand("select Name,Class,Section,RollNo from Student", con); 

     con.Open(); 

     SqlDataReader rdr = cmd.ExecuteReader(); 

     SqlBulkCopy sbc = new SqlBulkCopy("Data Source=DestinationServer;User Id=destinationserveruserid;Password=******;Initial Catalog=DeepakTransfer; Pooling=true; Max pool size=200; Min pool size=0"); 

     sbc.DestinationTableName = "StudentTrans"; 


     sbc.WriteToServer(rdr); 


     sbc.Close(); 
     rdr.Close(); 
     con.Close(); 

Le code me donne l'erreur comme: L'id locale '0' de la colonne source 'RollNo' et l'id locale '1033' de la colonne de destination ' La section "ne correspond pas.

Maintenant, après mappage de colonne, mon code s'exécute avec succès.

Mon code modifié:

SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder("Data Source=ServerName;User Id=userid;Password=****;Initial Catalog=Deepak;"); 

     SqlConnection con = new SqlConnection(cb.ConnectionString); 

     SqlCommand cmd = new SqlCommand("select Name,Class,Section,RollNo from Student", con); 

     con.Open(); 

     SqlDataReader rdr = cmd.ExecuteReader(); 


     SqlBulkCopy sbc = new SqlBulkCopy("Data Source=DestinationServer;User Id=destinationserveruserid;Password=******;Initial Catalog=DeepakTransfer;"); 

     sbc.DestinationTableName = "StudentTrans"; 

     sbc.ColumnMappings.Add("Name", "Name"); 
     sbc.ColumnMappings.Add("Class", "Class"); 
     sbc.ColumnMappings.Add("Section", "Section"); 
     sbc.ColumnMappings.Add("RollNo", "RollNo"); 

     sbc.WriteToServer(rdr); 
     sbc.Close(); 
     rdr.Close(); 
     con.Close(); 

Ce code est en cours d'exécution avec succès.

Essayez ceci et profitez-en.

1

Vous pouvez sélectionner des colonnes avec classement différent:

SELECT Foo COLLATE SQL_Latin1_General_CP1_CI_AS AS Bar FROM Baz 

Cela va convertir la collation de la colonne Foo au nouveau classement. Dans l'exemple ci-dessus, la colonne Foo est convertie en collation SQL_Latin1_General_CP1_CI_AS et nommée Bar dans la requête.

Vous devez ensuite ajouter ColumnMapping pour votre nouvelle colonne pour votre commande bulkcopy:

using (var bulkCopy = new SqlBulkCopy(connection)) 
{ 
    bulkCopy.DestinationTableName = "FooBars"; 
    bulkCopy.ColumnMappings.Add("Bar", "FooBar"); 
    bulkCopy.WriteToServer(reader); 
} 
1

cartographie simple colonne d'ajouter ne fonctionne pas pour moi. Et j'ai implémenté l'insertion via SqlBulkCopy et DataTable - celui-ci fonctionne très bien.

private void BulkCopyTable(string sourceConnection, string targetConnection, Table sTable, Table tTable) 
    { 
     using (SqlConnection sourceConn = new SqlConnection(sourceConnection)) 
     { 
      if (cbFixStructure.Checked) 
       CheckAndRecreateTarget(targetConnection, sTable, tTable); 

      string selectSql = "SELECT * FROM " + sTable.Schema + ".[" + sTable.Name + "]"; 

      string selectCntSql = "SELECT COUNT(*) FROM " + sTable.Schema + ".[" + sTable.Name + "] WITH(NOLOCK)"; 
      using (SqlCommand selectCmd = new SqlCommand(selectSql, sourceConn)) 
      { 
       selectCmd.CommandTimeout = 60 * 100 * 1000; 
       sourceConn.Open(); 
       Int64 totalCount = 0; 
       using (SqlCommand cntCommand = new SqlCommand(selectCntSql, sourceConn)) 
       { 
        cntCommand.CommandTimeout = 60 * 100 * 1000; 
        totalCount = Convert.ToInt64(cntCommand.ExecuteScalar()); 
       } 

       DataTable dtBuffer = new DataTable(); 
       var columns = sTable.Columns.Cast<Column>().Where(p => p.Computed == false).ToList(); 
       foreach (var clm in columns) 
       { 

        var sdt = clm.DataType.SqlDataType; 
        if (sdt == SqlDataType.UserDefinedDataType) 
        { 
         var lst = Enum.GetValues(typeof(SqlDataType)).Cast<SqlDataType>(); 
         sdt = lst.Where(p => p.ToString().ToLower() == TargetDataBase.UserDefinedDataTypes[clm.DataType.Name].SystemType.ToString()).First(); 
        } 


        dtBuffer.Columns.Add(new DataColumn(clm.Name, GetClrType(sdt))); 
       } 
       using (SqlDataReader reader = selectCmd.ExecuteReader()) 
       { 

        using (SqlBulkCopy blkCopy = new SqlBulkCopy(targetConnection, SqlBulkCopyOptions.KeepIdentity)) 
        { 
         blkCopy.BulkCopyTimeout = 60 * 100 * 1000; 
         blkCopy.DestinationTableName = sTable.Schema + ".[" + sTable.Name + "]"; 


         foreach (var colmn in columns) 
         { 
          blkCopy.ColumnMappings.Add(colmn.Name, colmn.Name); 
         } 


         int bufferCountLengthMax = 500; 
         int rowCnt = 0; 
         int globalCounter = 0; 
         while (reader.Read()) 
         { 
          var dataRow = dtBuffer.NewRow(); 
          foreach (var clm in columns) 
          { 
           dataRow[clm.Name] = reader[clm.Name]; 
          } 
          dtBuffer.Rows.Add(dataRow); 
          rowCnt++; 
          globalCounter++; 
          if (rowCnt >= bufferCountLengthMax) 
          { 
           dtBuffer.AcceptChanges(); 
           blkCopy.WriteToServer(dtBuffer); 
           rowCnt = 0; 
           dtBuffer.Rows.Clear(); 
           GC.Collect(); 
           DoLogText(String.Format("Table \"{0}\" copied rows {1} out of {2}", sTable.Schema + ".[" + sTable.Name + "]", globalCounter, totalCount)); 
          } 
         } 
         if (rowCnt > 0) 
         { 
          dtBuffer.AcceptChanges(); 
          blkCopy.WriteToServer(dtBuffer); 
          rowCnt = 0; 
          dtBuffer.Rows.Clear(); 
          GC.Collect(); 
          DoLogText(String.Format("Table \"{0}\" copied rows {1} out of {2}", sTable.Schema + ".[" + sTable.Name + "]", globalCounter, totalCount)); 
         } 

        } 
       } 
      } 

     } 
     DoLogText(String.Format("Table \"{0}\" done", sTable.Name)); 
    } 
+0

Cela ne répond pas vraiment à la question. Si vous avez une question différente, vous pouvez le demander en cliquant sur [Poser une question] (http://stackoverflow.com/questions/ask). Vous pouvez également [ajouter une prime] (http://stackoverflow.com/help/privileges/set-bounties) pour attirer plus d'attention à cette question une fois que vous avez assez de [réputation] (http://stackoverflow.com/help/ quoi-réputation). - [De l'examen] (/ review/low-quality-posts/11508752) – APH

+0

Oui, c'est une solution de contournement, celle qui fonctionne vraiment :). J'ai passé du temps sur d'autres solutions affichées ici mais aucune d'entre elles n'est réalisable. – user2932688

Questions connexes