martes, 22 de mayo de 2012

Error "El id. de configuración regional '3082' de la columna de origen 'NombreColumna' y el id. de configuración regional '1033' de la columna de destino 'NombreColumna' no coinciden." con la clase SqlBulkCopy


Introducción
Como ya lo he comentado con anterioridad, una de las maneras más eficientes de cargar datos a una tabla sql server es mediante el uso de la clase SqlBulkCopy.

Problema
En ocasiones, cuando se trabaja con diferentes servidores, puede suceder que cada uno de ellos tenga configurado diferente intercalación, sobre todo si se es principiante, como en mi caso, no nos dice nada el término Intercalación al momento de instalar una instancia de SQL Server y tampoco al crear una base de datos. El caso es que cuando estaba haciendo mis copias de respaldo de información entre servidores utilizando la clase SqlBulkCopy me pareció el siguiente mensaje de error:

El id. de configuración regional '3082' de la columna de origen 'NombreColumna' y el id. de configuración regional '1033' de la columna de destino 'NombreColumna' no coinciden.

Solución
Revisando en la red encontré dos posibles soluciones (seguramente hay más, pero solo probé estas):

1) Cambiar la intercalación en alguna de las columnas, ya sea de la tabla fuente o destino para hacerlas coincidir, con la instrucción SQL

ALTER TABLE NombreTabla ALTER COLUMN NombreColumna varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS

o,

2) Indicar la intercalación en el momento de recuperar la información con la siguiente instrucción SELECT:

SELECT NombreColumna COLLATE SQL_Latin1_General_CP1_CI_AS AS NombreColumna FROM NombreTabla

En mi caso, utilicé la segunda opción modificando el stored procedure que llenaba mi sqldatareader debido a que era lo que más convenía a lo que necesitaba.

Hasta la próxima!!

Problemas con la clase SqlBulkCopy en tablas con campos identity.


Introducción
Una de maneras más eficientes de cargar datos a una tabla sql server es mediante el uso de la clase SqlBulkCopy, en lo personal me ha sido de mucha utilidad cuando necesito "subir" una gran cantidad de información a servidores remotos.

Problema
Todo iba bien hasta que tuve que trabajar con una tabla "destino" que tiene un campo identity, ya que el objetivo era hacer un respaldo de la información, y para mantener las relaciones entre las tablas era necesario insertar valores en las columnas identity.

Solución
Consultando en la red encontré que se puede utilizar la instrucción IDENTITY_INSERT para habilitar y deshabilitar la inserción de valores en dichos campos, entonces adapté el código que utilizaba y quedó más o menos como sigue:


private static void BackupData()
{
   string dbSource = ConfigurationManager.ConnectionStrings["dbSource"].ConnectionString;
   string dbTarget = ConfigurationManager.ConnectionStrings["dbTarget"].ConnectionString;
   using (SqlConnection connection = new SqlConnection(dbTarget))
   {
      connection.Open();
      using (SqlCommand command = new SqlCommand())
      {
         command.Connection = connection;
         command.CommandType = CommandType.Text;
         command.CommandText = "SET IDENTITY_INSERT dbo.NombreTabla ON;"
         command.ExecuteNonQuery();
         using (SqlBulkCopy bulkcopy = new SqlBulkCopy(dbTarget, SqlBulkCopyOptions.KeepIdentity))
            {
               SqlDataReader reader = GetReader(dbSource,"SELECT * FROM dbo.Tabla");
               bulkcopy.DestinationTableName = "dbo.NombreTabla";
               bulkcopy.WriteToServer(reader);
               reader.Close();
            }
         command.CommandText = "SET IDENTITY_INSERT dbo.NombreTabla OFF;";
         command.ExecuteNonQuery();
      }
      connection.Close();
   }
}

En primer lugar se obtienen las cadenas de conexión del archivo de configuración de la aplicación, se abre una conexión a la base de datos destino para ejecutar los comandos con las instrucciones de habilitación/deshabilitación de la inserción en el campo identidad, una vez que se habilita la inserción en el campo identity, se crea una instancia de la clase SqlBulkCopy, he resaltado esta linea debido a que hay que tener cuidado al pasarle los parámetros adecuados al constructor, en este momento ya estamos listos para utilizar la instancia de la clase SqlBulkCopy, por último, lo que sigue es deshabilitar la inserción en el campo identidad, y cerrar la conexión abierta.

Espero no haber sido demasiado "breve" en la explicación y que esto sea de utilidad. Salud2!!