Ejemplo de SqlBulkCopy WriteToServer. ¿Qué estoy haciendo mal?

c# sql sqlbulkcopy sql-server

Pregunta

Esto puede ser largo, pero quiero explicar mi ejemplo

Tengo este Código:

#region [parent table]
DataTable dtParent = new DataTable();
DataColumn dc;

dc = new DataColumn();
dc.DataType = System.Type.GetType("System.Int32");
dc.ColumnName = "Id";
dc.Unique = true;
dc.AutoIncrement = true;
dtParent.Columns.Add(dc);

dc = new DataColumn();
dc.DataType = System.Type.GetType("System.String");
dc.ColumnName = "Title";
dc.Unique = false;
dtParent.Columns.Add(dc);

dtParent.TableName = "aTestSw";
dtParent.PrimaryKey = new DataColumn[] { dtParent.Columns[0] };
#endregion

#region [child table]
DataTable dtChild = new DataTable();

dc = new DataColumn();
dc.DataType = System.Type.GetType("System.Int32");
dc.ColumnName = "Id";
dc.Unique = true;
dc.AutoIncrement = true;
dtChild.Columns.Add(dc);

dc = new DataColumn();
dc.DataType = System.Type.GetType("System.Int32");
dc.ColumnName = "ParentId";
dc.Unique = false;
dtChild.Columns.Add(dc);

dc = new DataColumn();
dc.DataType = System.Type.GetType("System.String");
dc.ColumnName = "Description";
dc.Unique = false;
dtChild.Columns.Add(dc);

dtChild.TableName = "aTestSwChild";
dtChild.PrimaryKey = new DataColumn[] { dtChild.Columns[0] };
#endregion

DataSet DataSet1 = new DataSet();
DataSet1.Tables.Add(dtParent);
DataSet1.Tables.Add(dtChild);

#region [fk]
DataColumn parentColumn = dtParent.Columns["Id"];
DataColumn childColumn = dtChild.Columns["ParentId"];
DataRelation relParentChild = new DataRelation("ParentChild", 
    parentColumn, childColumn);
DataSet1.Relations.Add(relParentChild); 
#endregion

#region [fill parent]
DataRow dr2saveIn = dtParent.NewRow();
dr2saveIn["Title"] = "a";
dtParent.Rows.Add(dr2saveIn);

dr2saveIn = dtParent.NewRow();
dr2saveIn["Title"] = "b";
dtParent.Rows.Add(dr2saveIn);
#endregion

#region [fill child]
dr2saveIn = dtChild.NewRow();
dr2saveIn["Description"] = "c";
dr2saveIn["ParentId"] = dtParent.Rows[0]["Id"];
dtChild.Rows.Add(dr2saveIn);

dr2saveIn = dtChild.NewRow();
dr2saveIn["Description"] = "d";
dr2saveIn["ParentId"] = dtParent.Rows[1]["Id"];
dtChild.Rows.Add(dr2saveIn);   
#endregion

SqlBulkCopy bulkCopy = new SqlBulkCopy(
    "server=aaa;database=bbb;uid=ccc;password=ddd", 
    SqlBulkCopyOptions.TableLock);
bulkCopy.DestinationTableName = "dbo.aTestSw";
bulkCopy.WriteToServer(dtParent);
bulkCopy.DestinationTableName = "dbo.aTestSwChild";
bulkCopy.WriteToServer(dtChild);

Cuando lo ejecuté, obtuve datos que "parecían" correctos en la columna FK de la tabla secundaria. (0 y 1) Lo que pasa es que después de guardar, los datos entran en la base de datos, pero no está bien. En lugar de tener el ID de FK de la tabla principal, obtuve el 0 y el 1 del código C #. Nota: las tablas en el DB DO HAVE FK restringen en ellas. No puede agregar manualmente esas cosas, pero SqlBulkCopy WriteToServer no tiene ningún problema, escribe datos incorrectos de todos modos (es como si no se verificara por restricciones)

Mira las tablas:

CREATE TABLE [dbo].[aTestSw](
 [Id] [int] IDENTITY(1,1) NOT NULL,
 [Title] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
 CONSTRAINT [PK_aTestSw] PRIMARY KEY CLUSTERED 
(
 [Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


CREATE TABLE [dbo].[aTestSwChild](
 [Id] [int] IDENTITY(1,1) NOT NULL,
 [ParentId] [int] NOT NULL,
 [Description] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 CONSTRAINT [PK_aTestSwChild] PRIMARY KEY CLUSTERED 
(
 [Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[aTestSwChild]  WITH NOCHECK ADD  CONSTRAINT [FK_aTestSwChild_aTestSw] FOREIGN KEY([ParentId])
REFERENCES [dbo].[aTestSw] ([Id])

ALTER TABLE [dbo].[aTestSwChild] CHECK CONSTRAINT [FK_aTestSwChild_aTestSw]

Los resultados se ven así:

select * from aTestSw

Id          Title
16          a
17          b

select * from aTestSwChild

Id          ParentId    Description
12          0           c
13          1           d

¿Qué estoy haciendo mal? Probablemente no se suponga que tenga Id. Como esta en C #. ¿Pero cómo? ¿O es posible? Quiero decir, ¡¿cómo va a saber mi segundo bulkinsert el SQL? Identificación en el inserto?

Respuesta aceptada

uso de esta opción:

SqlBulkCopyOptions.KeepIdentity

antes de la acción de copia masiva, establezca CheckConstraints de su db en OFF. Después de esto inserte sus datos usando una copia masiva. cuando haya terminado todo su trabajo, establezca CheckConstraints en ON.

la opción al alza obliga a su db a mantener sus valores de identidad.


Respuesta popular

Por defecto, SqlBulkCopy convertirá sus claves foráneas en claves forzadas para no verificar. SqlBulkCopyOptions.CheckConstraints agregar la opción SqlBulkCopyOptions.CheckConstraints para mantener sus claves externas verificando todos los datos existentes y todos los nuevos.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow