2010-08-17 8 views
10

J'ai souvent affaire à des DataTables connectés à des contrôles de grille, la mise à jour personnalisée semble toujours produire beaucoup de code lié à DBNull.Value. J'ai vu une question similaire ici, mais pense qu'il doit y avoir une meilleure réponse:Traiter avec DBNull.Value

What is the best way to deal with DBNull's

Ce que je trouve est que je tends à résumer mes mises à jour de base de données dans les méthodes si je finis avec le code comme ci-dessous où je déplace la DBNull.Value à un type nullable puis retour pour la mise à jour:

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 
    } 

C'était juste un exemple du flux et non le code de travail. Je réalise que je peux faire des choses comme passer des objets ou avaler des problèmes de moulage en utilisant "comme type" pour obtenir DBUll directement à null mais ces deux semblent cacher des erreurs potentielles, j'aime le type de sécurité de la méthode avec des types nullables.

Existe-t-il une méthode plus propre pour ce faire tout en conservant la sécurité du type?

+0

Pourquoi n'utilisez-vous pas DataRow fortement typé directement? Vous avez mentionné que vous devez utiliser DataTables. Si ces tables de données sont fortement typées, vous pouvez envoyer une ligne de données à votre méthode. La ligne de données utilise déjà DBNull. –

Répondre

14

Deux (très) simples méthodes génériques d'assistance peut au moins se concentrer le test en un seul morceau de code:

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; 
} 

Ces méthodes peuvent être utilisées le cas échéant:

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

Recommande d'utiliser 'Convert.IsDBNull()' au lieu de 'value == DBNull.Value'. Et 'FromDBNull' /' ToDBNull' plutôt que seulement FromDB'/'ToDB', probablement. – abatishchev

+0

Cela semble plus facile merci je pensais que les génériques pourraient être la voie à suivre Je vais utiliser cela à moins que quelqu'un trouve une meilleure solution. – PeteT

+1

@abatishchev: Oui, utiliser 'Convert.IsDBNull' serait probablement plus élégant; encapsulant le test qui en soi n'est pas tout à fait le but de la méthode. En ce qui concerne le nommage, je peux convenir que 'FromDB' et' ToDB' sont un peu courts, bien que je préfère appeler les méthodes 'ToDBValue' et' FromDBValue' car elles ne convertissent pas toutes les valeurs en 'DBNull', mais renvoie plutôt la valeur transmise sous une forme utilisable lors de l'envoi ou de l'obtention de la base de données. –

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

ce qui signifie le même que

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

ou

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

(fonte supplémentaire à l'objet est nécessaire pour lever l'ambiguïté du type)

+0

@ petebob796: Ma solution est la plus marée, n'est ce pas? – abatishchev

1

Je ne vois pas quel est le problème avec as -casting et null coalescent.

as -casting est utilisé pour la lecture:

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

null coalescent est utilisé pour l'écriture:

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

ceux-ci sont complètement typesafe deux et ne le font pas des erreurs "cacher".

Si vous voulez vraiment, vous peut envelopper ceux-ci dans les méthodes statiques, si vous vous retrouvez avec ce pour la lecture:

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

et ceci pour l'écriture:

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

La méthode statique le code est légèrement plus propre dans l'écriture, mais l'intention est moins claire (surtout dans le cas de lecture).

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

Ceci est ma mise en œuvre de l'assistant DBNULL.L'utilisation est simple:

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