简体   繁体   中英

Generic way of handling DBNull

I have a lot of this type of logic in my code when using the SqlDataReader Is there a cleaner more generic way to handle this?

 if (reader["VisitingAddressId"] != DBNull.Value)
 {
     visitingAddress = new Address()
     {
         AddressId = Convert.ToInt64(reader["VisitingAddressId"]),
         Address1 = reader["VisitingAddress"].ToString(),
         AddressType = AddressType.VisitingAddress,
         PostalCode = reader["VisitingPostal"].ToString(),
         PostalDistrict = reader["VisitingPostalDistrict"].ToString()
      };
  }

 if (reader["PostalAddressId"] != DBNull.Value)
 {
     postalAddress = new Address()
     {
         AddressId = Convert.ToInt64(reader["PostalAddressId"]),
         Address1 = reader["PostalAddress"].ToString(),
         AddressType = AddressType.PostalAddress,
         PostalCode = reader["PostalPostal"].ToString(),
         PostalDistrict = reader["PostalPostalDistrict"].ToString()
      };
  }

I have these helper methods in a data service class (you could make them both static):

    public T CastDBValue<T>(object value)
    {
        return MapValue<T>(value);
    }   

    internal static T MapValue<T>(object value)
    {
        try
        {
            T result;
            result = value == DBNull.Value ? default(T) : (T)value;
            return result;
        }
        catch (InvalidCastException cex)
        {
            logger.ErrorFormat("Invalid cast while mapping db value '{0}' to type {1}. Error: {2}", value, typeof(T).Name, cex);
            throw new InvalidCastException(string.Format("Invalid cast while mapping db value '{0}' to type {1}. Error: {2}", value, typeof(T).Name, cex.Message));
        }
    }

Then in your mapping code, you just do:

AddressId = dataService.CastDBValue<int>(reader["AddressId"]));
if (AddressId > 0) { ... }

You could use a micro-ORM like Dapper: http://code.google.com/p/dapper-dot-net/

The multi mapping functionality would eliminate all that boiler plate code.

db.Query<Post,Address,Address,Post>("select * from Posts left join Address ... etc", 
 (post,vaddress,paddress) => 
  {
     post.VisitingAddress = vaddress; 
     post.PostalAddress = paddress; 
     return post; 
   });

What you are referring to are ORMs, of which there are many. NHibernate, Entity Framework, even ADO.NET (which you are already using) has support for relational datasets, although in that case you usually have to use a DataSet or derived, strongly-typed classes.

Check out the .NET section here for a list:

http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software

What are you requirements? Maybe we can narrow it down.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM