2016-09-25 7 views
0

SqlBulkCopyを使用してレコードをデータベースに一括挿入します。SqlBulkCopyがFOREIGN KEY制約エラーを返す

以下はそのコードです。私が気になるのは、SqlBulkCopyを使用するとFOREIGN KEY制約エラーが発生し、UNION ALLアプローチを使用するとまったく同じレコードが得られます。私はここで間違って何をしていますか?

CREATE TABLE [dbo].[Kits] 
(
    [KitId] [nvarchar](15) NOT NULL, 
    CONSTRAINT [PK_Kits] PRIMARY KEY CLUSTERED ([KitId] ASC) 
       WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[KitStatuses] 
(
    [KitStatusId] [int] IDENTITY(1,1) NOT NULL, 
    [KitId] [nvarchar](15) NOT NULL, 
    [StatusId] [int] NOT NULL, 
    [StatusDate] [datetime] NOT NULL, 
    [IsActiveStatus] [bit] NOT NULL, 

    CONSTRAINT [PK_KitStatuses] PRIMARY KEY CLUSTERED([KitStatusId] ASC) 
       WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], 
    CONSTRAINT [IX_KitStatuses_KitId_KitStatus] 
     UNIQUE NONCLUSTERED ([KitId] ASC, [KitStatusId] ASC) 
       WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[Statuses] 
(
    [StatusId] [int] IDENTITY(1,1) NOT NULL, 
    [StatusName] [nvarchar](50) NOT NULL, 

    CONSTRAINT [PK_Statuses] PRIMARY KEY CLUSTERED ([StatusId] ASC) 
       WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
         IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
         ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

ALTER TABLE [dbo].[KitStatuses] 
    ADD CONSTRAINT [DF_KitStatuses_StatusDate] 
     DEFAULT (getdate()) FOR [StatusDate] 

ALTER TABLE [dbo].[KitStatuses] 
    ADD CONSTRAINT [DF_KitStatuses_IsActiveStatus] 
     DEFAULT ((1)) FOR [IsActiveStatus] 

ALTER TABLE [dbo].[KitStatuses] WITH CHECK 
    ADD CONSTRAINT [FK_KitStatuses_Kits] 
     FOREIGN KEY([KitId]) REFERENCES [dbo].[Kits] ([KitId]) 

ALTER TABLE [dbo].[KitStatuses] CHECK CONSTRAINT [FK_KitStatuses_Kits] 

ALTER TABLE [dbo].[KitStatuses] WITH CHECK 
    ADD CONSTRAINT [FK_KitStatuses_Statuses] 
     FOREIGN KEY([StatusId]) REFERENCES [dbo].[Statuses] ([StatusId]) 

ALTER TABLE [dbo].[KitStatuses] CHECK CONSTRAINT [FK_KitStatuses_Statuses] 

私は技術の下に使用しています::DB接続の

  • エンタープライズライブラリのデータアクセスブロックの下

    public partial class Repository 
    { 
        public bool InsertResult(List<string> kitIds) 
        { 
         if (kitIds == null || kitIds.Count == 0) 
          return false; 
    
         using (var connection = (SqlConnection)_database.CreateConnection()) 
         { 
          connection.Open(); 
    
          using (var transaction = connection.BeginTransaction()) 
          { 
           try 
           { 
            using (SqlBulkCopy copy = new SqlBulkCopy(connection, SqlBulkCopyOptions.CheckConstraints, transaction)) 
            { 
             /*This works*/ 
             var sb = new StringBuilder(2048); 
             sb.AppendLine("INSERT INTO KITSTATUSES (KitId, StatusId, IsActiveStatus) "); 
    
             for (int i = 0; i < kitIds.Count; i++) 
             { 
              sb.AppendLine($"SELECT '{kitIds[i]}', {(int)StatusOfKit.ResultUploaded}, 1"); 
              sb.AppendLine("UNION ALL "); 
             } 
    
             sb.Remove(sb.Length - 12, 12); 
             connection.Execute(sb.ToString(), null, transaction); 
    
             /*DOES NOT WORK and throws error: 
             * The INSERT statement conflicted with the FOREIGN KEY constraint "FK_KitStatuses_Kits". The conflict occurred in database "GeneBlueprint", table "dbo.Kits", column 'KitId'. 
             * The statement has been terminated. 
             var kitStatuses = kitIds.Select(k => new KitStatus { KitId = k, IsActiveStatus = true, StatusId = (int)StatusOfKit.ResultUploaded }).ToList(); 
             using (var reader = ObjectReader.Create(kitStatuses, "KitId", "StatusId", "IsActiveStatus")) 
             { 
              //Verify that reader has right values 
              //while (reader.Read()) 
              //{ 
              // Debug.WriteLine($"KitId: {reader.GetFieldValue<string>(0)}, StatusId: {reader.GetFieldValue<int>(1)}, IActiveStatus: {reader.GetFieldValue<bool>(2)}, StatusDate: {reader.GetFieldValue<DateTime>(3)}"); 
              //} 
              copy.DestinationTableName = "KitStatuses"; 
              copy.WriteToServer(reader); 
             } 
             */ 
    
             /*DOES NOT WORK and throws error 
             * The INSERT statement conflicted with the FOREIGN KEY constraint "FK_KitStatuses_Kits". The conflict occurred in database "GeneBlueprint", table "dbo.Kits", column 'KitId'. 
             * The statement has been terminated. 
             DataTable dt = new DataTable(); 
             dt.Columns.Add(new DataColumn() { ColumnName = "KitId", DataType = typeof(string), MaxLength = 15, AllowDBNull = false, AutoIncrement = false }); 
             dt.Columns.Add(new DataColumn() { ColumnName = "StatusId", DataType = typeof(int), AllowDBNull = false, AutoIncrement = false, DefaultValue = 8 }); 
             dt.Columns.Add(new DataColumn() { ColumnName = "IsActiveStatus", DataType = typeof(bool), AllowDBNull = false, AutoIncrement = false, DefaultValue = true }); 
             for (int i = 0; i < kitIds.Count; i++) 
             { 
              var row = dt.NewRow(); 
              row[0] = kitIds[i]; 
              row[1] = 8; 
              row[2] = true; 
              dt.Rows.Add(row); 
             } 
    
             using (var reader = ObjectReader.Create(kitStatuses, "KitId", "StatusId", "IsActiveStatus", "StatusDate")) 
             { 
              copy.DestinationTableName = "KitStatuses"; 
              copy.WriteToServer(dt); 
             } 
             */ 
            } 
    
            transaction.Commit(); 
           } 
           catch (Exception) 
           { 
            transaction.Rollback(); 
            throw; 
           } 
          } 
         } 
    
         return true; 
        } 
    } 
    

    はこの質問に関連するテーブル用のスクリプトです。

  • Fast memberは、問題が発生しているのDataReader

答えて

1

にリストを変換するには、インサートSqlBulkCopy理由:

  • KitId列でStatusId列でKitId
  • StatusId

オートマップは実際にスマートではありません...

はまず、すべての列は、順序によってマッピングされる。

  • のDataColumn 0(KitId)TableColumnの0にマッピングされた(KitStatusId)は
  • のDataColumn 1(StatusId)はTableColumn1(KitIt)
  • のDataColumn 2(IsActiveStatus)にマッピングTableColumn2にマッピングされた(StatusId)

SqlBulkCopyコード

internal void CreateDefaultMapping(int columnCount) 
{ 
    for (int index = 0; index < columnCount; ++index) 
    this.InnerList.Add((object) new SqlBulkCopyColumnMapping(index, index)); 
} 

2つ目は、KitStatusIdがIDなので、AutoMappingは次に使用可能な列にマップしようとします。また、IsActiveStatusがStatusIdの種類と一致しないため、AutoMappingはKitIdをStatusId列にマッピングします。あなたが生成されたSQLを見れば

、あなたはこれが唯一のいくつかのエラーにつながる自動マッピングを信頼したことがない、IsActiveStatusは要するに

insert bulk KitStatuses ([KitId] NVarChar(15) COLLATE SQL_Latin1_General_CP1_CI_AS, [StatusId] Int) with (CHECK_CONSTRAINTS) 

にマッピングされていないが表示されます。

は、明示的に代わり

copy.ColumnMappings.Add("KitId", "KitId"); 
copy.ColumnMappings.Add("StatusId", "StatusId"); 
copy.ColumnMappings.Add("IsActiveStatus", "IsActiveStatus"); 
+0

が、私は決して新しい問題である可能性があり、そのあなたのコラムの地図。私はマッピングを追加した後、それはちょうど働いた。 – ndd

+0

あなたのシナリオを試してみるととても驚きました。私はいつもアイデンティティ列は無視され、すべてのマッピングが次の列に移されましたが、これは多くの意味をなす必要があります。しかし、私はあなたのコードを試したときに、最初の列だけが最後の列に移動されました。 –

関連する問題