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

Reply via email to