2009-10-06 5 views
1

Disons que j'ai une classe personnalisée comme celui-ci:Comment gérer les valeurs NULL dans mes objets métier

public class Customer  
{   
public int CustomerID { get; set; }   
public string CompanyName { get; set; }   
public string BusinessAddress { get; set; }   
public string Phone { get; set; } 
public int ParentID { get; set; } 
} 

je crée des objets personnalisés à partir de la base de données à l'aide d'un datareader. Ex:

while (dr.Read()) 
    { 
    listCustomers.Add(new Customer(
      Convert.ToInt32(dr["CustomerID"]), 
      Convert.ToString(dr["CompanyName"]), 
      Convert.ToString(dr["BusinessAddress"]), 
      Convert.ToString(dr["Phone"]), 
      Convert.ToInt32(dr["ParentID"]), 
) 

ParentID peut être NULL dans la base de données (et je ne peux pas le changer). Quand c'est nul, la conversion échoue évidemment.

Comment dois-je gérer les valeurs nulles extraites de la base de données pour remplir mes objets métier? Serait-il bon d'utiliser des Types Nullables dans ma classe personnalisée? D'autres conseils?

Répondre

6

Absolument. Les types nullables sont parfaitement bien. Sinon, vous devrez trouver une convention stupide a-la "quand ParentID est -1, cela signifie que Customer n'a pas de parent". Les types nullables appliquent ce "by design": s'il n'y a pas de parent, ParentID sera null.

Comme pour hydrater vos objets, pensez à utiliser des outils ORM (tels que NHibernate ou BLToolkit), puisque vous ne voulez pas vraiment dépenser 50% de votre écriture de développement des dents requêtes SQL et peuplant vos objets à partir d'un lecteur de données

2

Que diriez-vous d'ajouter des aides comme ceci:

static string safeGetStringFromDB(IDataReader dr, string strField) 
    { 
     int nIndex = dr.GetOrdinal(strField); 
     if (dr.IsDBNull(nIndex)) 
      return string.Empty; 
     return dr.GetString(nIndex); 
    } 
1

Vous pouvez créer de telles méthodes d'assistance:

 static T Map<T>(object obj, Func<object, T> map, T def) 
    { 
     if (obj != null) 
     { 
      return map(obj); 
     } 
     return def; 
    } 

    static T Map<T>(object obj, Func<object, T> map) 
    { 
     return Map<T>(obj, map, default(T)); 
    } 

Et utilisez-les comme:

  object o = 1; 
     var t = Map(o, Convert.ToInt32, 0); // with default value 
     var t2 = Map(o, Convert.ToInt32); // or without default value 
+0

Trop de code juste pour vérifier un homme NULL. – Shiva

0

ParentID est une chaîne dans votre classe et vous la convertissez en Int32. Mais cela mis à part: Vous connaissez la base de données, vous savez donc quels champs peuvent être NULL. Je rendrais tous ces champs nullables dans l'objet de données, car à mon avis, c'est le meilleur moyen de modéliser la base de données aussi près que possible.

2

Les types nullables conviennent aux champs Nullable.

gérer l'affectation avec un ternaire: -

ParentID = (dr["ParentID"] is DBNull) ? null : (int)dr["ParentID"]; 

En outre, vous n'avez pas besoin d'utiliser Convertir si vous savez ce que vos champs db sont sous-jacents et de leurs représentations .NET.

Je limite l'utilisation de convertir aux situations où je sais que les types sont différents (disons int à la chaîne).

Quand je connais le type correspondant .NET, je vais tout simplement jeté: -

listCustomers.Add(new Customer(
      (int)dr["CustomerID"], 
      (string)dr["CompanyName"], 
      (string)dr["BusinessAddress"], 
      (string)dr["Phone"], 
      (dr["ParentID"] is DBNull) ? null : (int)dr["ParentID"])); 

Enfin, lors de l'utilisation des types nullable, sachez que la surcharge d'une méthode peut être un problème potentiel.

Prenons les exemples suivants: -

public void Populate(int? facilityId, string name, bool? somethingElse)... 
public void Populate(string facilityCode, string name, bool? somethingElse)... 

Même nombre d'arguments, tous params potentiellement nulle. Lorsque le premier paramètre est null, vous pourriez être surpris de l'interprétation que votre compilateur finit par prendre. A m'a attrapé avant, de toute façon.

+0

Merci! Je pense que la dernière partie devrait être (int?) Dr ["ParentID"] au lieu de (int) dr ["ParentID"], sinon le compilateur se plaindra. – Max

3

Utilisez des types nullables dans vos objets métier. Vous pouvez ensuite utiliser une méthode auxiliaire générique comme celle-ci pour extraire les champs nullables de la base de données.

public static T? GetValue<T>(IDataRecord record, string columnName) 
    where T : struct 
{ 
    int columnIndex = record.GetOrdinal(columnName); 
    if (record.IsDBNull(columnIndex)) 
     return null; 
    else 
     return (T)Convert.ChangeType(record[columnIndex], typeof(T)); 
} 

Donc, si vous ParentId est déclarée comme int? vous procédez comme suit lors du chargement d'une ligne.

obj.ParentId = GetValue<int>(dr, "ParentId"); 
Questions connexes