Пример SqlBulkCopy WriteToServer. Что я делаю неправильно?

Это может быть долго, но я хочу объяснить свой пример

Я получил этот код:

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

Когда я запускаю его, я получаю данные, которые «выглядят» правильно в столбце FK дочерней таблицы. (0 и 1) Дело в том, что после сохранения данные попадают в базу, но не все в порядке. Вместо идентификатора FK из родительской таблицы я получил 0 и 1 из кода C#. Примечание. Таблицы в БД ДЕЙСТВИТЕЛЬНО ИМЕЮТ FK Constrain. Вы не можете добавить это вручную, но SqlBulkCopy WriteToServer не имеет проблем, все равно записывает неправильные данные (как будто он не проверяется на ограничения)

Посмотрите таблицы:

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]

Результаты выглядят следующим образом:

select * from aTestSw

Id          Title
16          a
17          b

select * from aTestSwChild

Id          ParentId    Description
12          0           c
13          1           d

Что я делаю неправильно? Вероятно, я не должен получать такие идентификаторы в С#. Но как? Или это вообще возможно? Я имею в виду, как мой второй объемный ввод узнает SQL!!!! идентификатор на вставке?


person Ash    schedule 10.02.2010    source источник


Ответы (2)


использование этого варианта:

SqlBulkCopyOptions.KeepIdentity

перед массовым копированием установите CheckConstraints вашей базы данных в положение OFF. после этого вставьте свои данные, используя массовое копирование. когда вся ваша работа будет выполнена, установите CheckConstraints в положение ON.

опция upside заставляет вашу базу данных сохранять ваши идентификационные значения.

person masoud ramezani    schedule 12.02.2010
comment
что если в БД есть запись с id = 1 и я добавлю новую? - person Ash; 12.02.2010

По умолчанию SqlBulkCopy превратит ваши внешние ключи во внешние ключи без проверки. Вам нужно добавить опцию SqlBulkCopyOptions.CheckConstraints, чтобы ваши внешние ключи проверяли все существующие и все новые данные.

person jhilden    schedule 27.02.2013