Reputation: 11138
I have on one side an Access database, where Tbl_Application.id_connexion
is a field with a Guid
type (called 'replication ID' in ms Access terminology).
I am collecting some data from this Tbl_Application table through a DataRow[]
array, dr_Tbl_Application
. The following code reads the first DataRow:
private Guid? mid_connexion = null;
mid_connexion = (Guid)dr_Tbl_Application[0]["id_connexion"]
Everything is ok as long as Tbl_Application.id_connexion
holds a value. In case this field does not hold a value, I will get the following error:
InvalidCastException was unhandled
And these are some things I can see in the immediate window:
? dr_Programme[0]["id_Connexion"]
{}
? dr_Programme[0]["id_Connexion"].GetType()
{Name = "DBNull" FullName = "System.DBNull"}
? dr_Programme[0]["id_Connexion"] is System.DBNull
true
So, to avoid my exception, I guess I'd better test before transfering a unique identifier value from a field in a database to a local variable. This said, I am still bothered by my finding, and I'd like to dig deeper into this issue.
My questions are the following:
System.DBNull
?Edit on question 2:
? dr_Programme[0]["id_Connexion"].GetType()
returns System.Guid type when the corresponding field is populated in the original table, while
? dr_Programme[0]["id_Connexion"].GetType()
returns System.DBNull type when the field is null (or not populated) in the original table ...
Upvotes: 4
Views: 3663
Reputation: 332
Use this:
public static class SomeClass
{
public static Guid? With(this Guid? o, object x)
{
if (x is System.DBNull) return null;
return o = (Guid)x;
}
}
Upvotes: 1
Reputation: 726489
DBNull
implements the Null Object Design Pattern to address the difference between DB returning a NULL vs. not returning anything. Unfortunately, the lack of its intuitiveness keeps tripping up programmers for many years.
The best you can do is wrapping it in a generic method, like this:
public static T? GetNullable<T>(object obj) where T : struct
{
if (obj == DBNull.Value) return null;
return (T?)obj;
}
Now you can call this method like this:
mid_connexion = GetNullable<Guid>(dr_Tbl_Application[0]["id_connexion"]);
Upvotes: 4
Reputation: 9474
I'm afraid that you will have to keep checking for DBNull, unless you design your DB schema to not allow them to occur. Also note that DBNull is different from C# null.
You can probably make the code slightly less verbose by using the Convert class in C#. In general it will perform default conversions rather than throw an exception (e.g. when it encounters a null value; note that it does not to my knowledge know how to deal with DBNull values, so you'll need to deal with those manually).
My recommendation would be to create a set of extension methods to do the necessary work:
public static class AccessExtensions
{
public static Guid GetGuidOrEmpty( this IDbReader reader, string columnName )
{
// all the code to check for DBNull and conversions goes here
// ...
return hasValue ? value : Guid.Empty;
}
}
One last word of caution is that Access can be funny about GUIDs, such as requiring strings for insert/update but returning GUID types on select. This may have improved since I tried it in 2003 or thereabouts.
Upvotes: 1