2010-08-17 4 views
10

자주 그리드 컨트롤에 연결된 DataTables를 다루어야하는데, 커스텀 업데이트는 항상 DBNull.Value와 관련된 많은 코드를 생성하는 것으로 보입니다. 여기 비슷한 질문을 보았지만 더 나은 답이 있어야합니다 생각 :DBNull.Value 다루기

What is the best way to deal with DBNull's

나는 내가 이동 어디 다음과 같은 코드로 끝날 수 있도록 나는 방법에 내 데이터베이스 업데이트를 캡슐화하는 경향이있다 찾을 것은 다시 업데이트에 대한 nullable 형식에 DBNull.value과 : 그냥 흐름의 예제 코드를 작동하지 않는

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    Boolean? requiresSupport = null; 
    if (grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) != DBNull.Value) 
     requiresSupport = (bool)grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport); 

    AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport) 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID,    
     bool? requiresSupport) 
    { 
     List<SqlParameter> parameters = new List<SqlParameter>(); 

     parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
     parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 

     if (requiresSupport == null) 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = DBNull.Value }); 
     else 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = requiresSupport }); 

     //execute sql query here to do update 
    } 

. 나는 객체 통과 또는 잠재적 인 캐스팅 문제를 "유형"을 사용하여 null로 곧바로 가져올 수 있음을 알지만 두 가지 모두 잠재적 인 오류를 숨기는 것처럼 보입니다. nullable 유형이있는 메소드의 유형 안전성을 좋아합니다.

유형 안전성을 유지하면서 더 깨끗한 방법이 있습니까?

+0

강력하게 형식화 된 DataRow를 직접 사용하지 않는 이유는 무엇입니까? 당신은 DataTables를 사용해야만한다고 언급했습니다. 이러한 데이터 테이블을 강하게 입력하면 메서드에 데이터 행을 보낼 수 있습니다. 데이터 행은 이미 DBNull을 사용합니다. –

답변

14

(매우) 간단한 일반적인 헬퍼 방법 중 몇 적어도 하나의 코드로 테스트를 집중할 수 있습니다

static T FromDB<T>(object value) 
{ 
    return value == DBNull.Value ? default(T) : (T)value; 
} 

static object ToDB<T>(T value) 
{ 
    return value == null ? (object) DBNull.Value : value; 
} 

이러한 방법은 다음 사용할 수있는 적절한 :

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    AdditionalSupport.UpdateASRecord(year, studentID, 
     FromDB<Boolean?>(grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport))); 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID, 
     bool? requiresSupport) 
{ 
    List<SqlParameter> parameters = new List<SqlParameter>(); 

    parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
    parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 
    parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = ToDB(requiresSupport) }); 

    //execute sql query here to do update 
} 
+2

'value == DBNull.Value' 대신'Convert.IsDBNull()'을 사용하는 것을 권장합니다. 그리고 FromDB' /'ToDB'보다는 오히려'FromDBNull' /'ToDBNull'을 사용해야합니다. – abatishchev

+0

제네릭이 더 좋은 솔루션을 제시하지 않는다면 제네릭을 사용할 수있는 방법이 될 수 있다고 생각합니다. – PeteT

+1

@abatishchev : 네,'Convert.IsDBNull'을 사용하면 아마도 더 우아 할 것입니다; 그 자체가 그 방법의 목적이 아닌 시험을 캡슐화한다. 이름에 대해서는'ToDBValue'와'FromDBValue' 메소드를 호출하는 것이 아니라 모든 값을'DBNull'으로 변환하지 않기 때문에'FromDB'와'ToDB'가 다소 짧다고 동의 할 수 있습니다. 오히려 전달 된 값을 DB로 보내거나 가져올 때 사용할 수있는 형식으로 반환합니다. –

0
parameters.Add("@requires_support", SqlDbType.Bit).Value = (object)requiresSupport ?? DBNull.Value; 

은 같은 것을 의미합니다.

parameters.Add("@requires_support", SqlDbType.Bit).Value = (requiresSupport != null) ? (object)requiresSupport : DBNull.Value; 

또는

if (requiresSupport != null) 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = requiresSupport 
else 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = DBNull.Value; 

+0

@ petebob796 : 내 해결책은 가장 많은 조류일까요? – abatishchev

1

내가 as -casting와 null 병합 뭐가 잘못 표시되지 않습니다 (반대하기 위해 추가 캐스트는 유형의 모호성을 제거하기 위해 필요합니다).

as -casting 읽기 위해 사용됩니다

bool? requiresSupport = 
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport); 

null 병합을 쓰기 위해 사용된다 : 이러한

parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) 
    { Value = studentID }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = (object)requiresSupport ?? DBNull.Value }); 

완전히 형태 보증하고 "숨기기"오류하지 않습니다.

//bool? requiresSupport = 
// grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
bool? requiresSupport = FromDBValue<bool?>(
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport)); 

이 쓰기를 위해 :

//parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
// { Value = (object)requiresSupport ?? DBNull.Value }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = ToDBValue(requiresSupport) }); 

정적 방법 당신이 정말로 원하는 경우 읽기이와 끝까지 있도록

, 당신은 , 정적 방법으로 이러한 포장 할 수 있습니다 코드는 쓰기 케이스에서 약간 더 깨끗하지만 의도는 덜 명확합니다 (특히 읽기 경우).

0
public static object DbNullable<T>(T? value) where T : struct 
{ 
    if (value.HasValue) 
    { 
     return value.Value; 
    } 
    return DBNull.Value; 
} 

public static object ToDbNullable<T>(this T? value) where T : struct 
{ 
    return DbNullable(value); 
} 

이것은 DBNULL 도우미를 구현 한 것입니다.사용법은 간단합니다.

new SqlParameter("Option1", option1.ToDbNullable())