2008-09-26 1 views
6

C# 코드GUID 기본 키와 기본 newsequentialid()가있는 테이블에서 SQLBulkCopy를 사용하는 방법은 무엇입니까?

 tran = connection.BeginTransaction(); 
     SqlBulkCopy sqlCopy = new SqlBulkCopy(connection,SqlBulkCopyOptions.Default, tran);    

     sqlCopy.DestinationTableName = "MyTable";    
     sqlCopy.WriteToServer(dataTable); 

당신에게 오류를 제공과 함께 GUID 기본 키 및 기본 NEWSEQUENTIALID()

예를 들어

CREATE TABLE [dbo].[MyTable](
[MyPrimaryKey] [uniqueidentifier] NOT NULL CONSTRAINT [MyConstraint] DEFAULT (newsequentialid()), 
[Status] [int] NULL, 
[Priority] [int] NULL, 
CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED 
(
[MyPrimaryKey] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

와 함께 테이블에 SqlBulkCopy의를 사용하는 경우 ...

열 'MyPrimaryKey'는 DBNull.Value를 허용하지 않습니다.

나는 SqlBulkCopyOptions을 노려 보았습니다. 작동하는 유일한 방법은 null을 허용하고 기본 키를 제거하도록 MyPrimaryKey 필드를 설정하는 것입니다.

이 문제의 해결 방법이 있다면 누구든지 알 수 있습니까? 또는 (테이블 구조 변경 이외의) 해결 방법이 없다는 것을 확인할 수 있습니까?

답변

0

로드중인 데이터에서 MyPrimaryKey 필드를 제거하거나 테이블 구조를 수정하는 것만 가능합니다.

값이없는 필드가 있으면 필드에 null을 강제로 넣으려고한다는 사실을 SQL에 알려주고 있습니다. 이는 분명히 허용되지 않습니다.

11

열 매핑을 설정해야합니다. 첫 번째 통화

sqlCopy.ColumnMappings.Clear(); 

는 다음이 대량 복사가 MyPrimaryKey 컬럼에 삽입하는 일을 그만 것입니다 만 상태 및 우선 순위 컬럼에 삽입 의미

sqlBulkCopy.ColumnMappings.Add("Status", "Status"); 
sqlBulkCopy.ColumnMappings.Add("Priority", "Priority"); 

호출합니다.

+0

우수,이 도움이되었습니다 !!!!! – HaBo

+0

JRummell, GUID 열은 SQLBULKCOPY 명령을 통해 삽입 된 각 행에 대해 새 값을 자동으로 생성합니까? 미리 감사드립니다. –

0

작성한 컬럼 세트에서 데이터베이스 생성 컬럼을 제거하면 필요한 작업입니다.

대부분의 데이터베이스 작업에는 LINQ-to-SQL을 사용하지만 L2S는 약간 느리기 때문에 다른 레코드를 한 번에 삽입하는 다른 방법을 사용합니다.

내부적으로 SqlBulkCopy을 사용하는 모든 테이블에서 사용할 수있는 BulkInsertAll<>이라는 일반적인 방법이 있습니다. 제네릭 형식의 속성을 기반으로 리플렉션을 사용하여 동적으로 열을 생성합니다. ColumnAttribute은 .dbml 파일에서 생성 된 .cs 파일에서 찾을 수 있습니다. 여기에서 guid 기본 키 열을 IsDbGenerated="true"으로 지정했습니다.

public void BulkInsertAll<T>(IEnumerable<T> entities) { 
    entities = entities.ToArray(); 

    string cs = Connection.ConnectionString; 
    var conn = new SqlConnection(cs); 
    conn.Open(); 

    Type t = typeof(T); 

    var tableAttribute = (TableAttribute) t.GetCustomAttributes(
     typeof(TableAttribute), false 
    ).Single(); 

    var bulkCopy = new SqlBulkCopy(conn) { 
     DestinationTableName = tableAttribute.Name 
    }; 

    var properties = t.GetProperties().Where(EventTypeFilter); 

    // This will prevent the bulk insert from attempting to update DBGenerated columns 
    // Without, inserts with a guid pk will fail to get the generated sequential id 
    // If uninitialized guids are passed to the DB, it will throw duplicate key exceptions 
    properties = properties.Where( 
     x => !x.GetCustomAttributes(typeof(ColumnAttribute), false) 
      .Cast<ColumnAttribute>().Any(attr => attr.IsDbGenerated) 
    ); 

    var table = new DataTable(); 

    foreach(var property in properties) { 
     Type propertyType = property.PropertyType; 
     if(propertyType.IsGenericType && 
      propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) { 
      propertyType = Nullable.GetUnderlyingType(propertyType); 
     } 

     table.Columns.Add(new DataColumn(property.Name, propertyType)); 
    } 

    foreach(var entity in entities) { 
     table.Rows.Add( 
      properties.Select( 
       property => GetPropertyValue(property.GetValue(entity, null)) 
      ).ToArray() 
     ); 
    } 

    //specify the mapping for SqlBulk Upload 
    foreach(var col in properties) { 
     bulkCopy.ColumnMappings.Add(col.Name, col.Name); 
    } 

    bulkCopy.WriteToServer(table); 

    conn.Close(); 
} 


private bool EventTypeFilter(System.Reflection.PropertyInfo p) { 
    var attribute = Attribute.GetCustomAttribute(p, 
     typeof(AssociationAttribute)) as AssociationAttribute; 

    if(attribute == null) return true; 
    if(attribute.IsForeignKey == false) return true; 

    return false; 
} 

private object GetPropertyValue(object o) { 
    if(o == null) 
     return DBNull.Value; 
    return o; 
} 

그리고 이것은 정상적으로 작동합니다. 엔티티는 새로 할당 된 Guid로 업데이트되지 않으므로 다른 쿼리를 만들어야 만 새로운 행에 속성 생성 가이드가 데이터베이스에 생성됩니다.

.Where 필터를 EventTypeFilter 메서드에 넣을 수는 있지만 대부분을 작성한 사람이 아니며 모든 것을 조정할 필요가 없습니다.

관련 문제