Hi!
I'm the author of Sooda (http://www.sooda.org) who happens to be looking at
alternative open-source O/R mapping solutions. I recently joined the iBatis
mailing lists and I thought I might share some of my experiences on the
"nullable" subject.
I faced the same problem in SoodaStubGen utility - namely "how should I
expose the null values to the user code". This is not a problem for object
references, because Sooda represents them as objects instead of key values,
but can be a problem for null values of primitive types.
There are the following options which you can use when allowing null values:
1. Use boxing:
You represent "nullable integer" as "System.Object which happens to have
Int32 boxed".
The representation is:
object Field1
{
get { return ...; }
set { ... }
}
Usage:
o.Field1 = null; // assignment of null
o.Field1 = 3; // assignment of not-null
o.Field1 == null; // comparison to null
(int)o.Field1 == 3; // comparison to not-null. Throws on null.
Pros:
null value is exactly the same null as for other objects
Cons:
You loose type safety and require many casts.
Potentially more memory allocations because of boxing
2. Use System.Data.SqlTypes structures
The representation is:
SqlInt32 Field1
{
get { return ...; }
set { ...}
}
Usage:
o.Field1 = SqlInt32.Null; // assignment of null
o.Field1 = 3; // assignment of not-null
o.Field1.IsNull // comparison to null
o.Field1.Value == 3 // comparison to not-null. Throws on null.
Pros:
type-safe nulls (SqlInt32.Null != SqlDouble.Null)
quite fast and uses low memory (uses structures instead of boxing)
full compile-time type checking possible
uses operator overloading so common operations look "pretty"
Cons:
ugly null syntax
3. Use a pair of properties to represent null. Some naming convention is
required, like "IsNull" suffix or "Has" prefix. This is similar to what
XSD.exe does for nullable datetime elements in XML.
The representation is:
SqlInt32 Field1
{
get { return ...; }
set { ... }
}
bool Field1IsNull
{
get { ... }
set { ... }
}
Usage:
o.Field1IsNull = true; // assignment of null
o.Field1 = 3; // assignment of not-null;
o.Field1IsNull; // comparison to null
o.Field1 == 3; // comparison to not null, can be made to throw on null
4. Use .NET 2.0 nullable types.
Representation:
int? Field1
{
get { }
set { }
}
Usage:
o.Field1 = null; // assignment of null
o.Field1 = 3; // assignment of not null
o.Field1 == null; // comparison to null
(int)o.Field1 == 3; // comparison to not null, throws on null
Pros:
Full type safety
No boxing - uses generic structure
Cons:
None that I can see right now.
5. Use the NullableTypes library available at
http://nullabletypes.sourceforge.net/ I haven't evaluated it yet, but it
looks like it's similar to System.Data.SqlTypes but has some added
functionality and bugs fixed:
Some comparison can be found here.
http://nullabletypes.sourceforge.net/sqltypes.html
Sooda currently supports options #1,#2 and #3 and will support #4 when .NET
2.0 version becomes available.
--
Jaroslaw Kowalski
http://blog.jkowalski.net/
----- Original Message -----
From: Clinton Begin
To: [email protected]
Sent: Thursday, August 25, 2005 5:39 AM
Subject: Dealing with non-nullable C# "primitives"
Hey guys,
Who would have thought that I would post a question to the user forum eh?
My question is: What's the deal with non-nullable "primitive" types in C# ?
Like seriously, Int32 extends Object (via struct?), and it's a class......so
why can't it be set to null?
Whoops, that's a question for Microsoft. :-)
Anyway, a better question for this list is: What pattern do you use to
represent NULL types from the database. That is, say you have an NUMERIC
NULL field, and you want to map it to a class with a field/property of type
int (Int32). It won't work because int can't represent null. So ...
Do you?
A) Write your own "NullableInt32" class and use a more complex mapping?
B) Use null value replacement and set the primitive to a magic number?
C) Something else?
Thanks much!
Clinton