CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Brendan Tompkins [MVP]

Blog First. Ask Questions Later.

System.DateTime in Entities - Dammed if you're nullable, Dammed if you're not

Often when designing my entity objects, I've used System.Object instead of System.DateTime for dates that can be nullable.  (Sidebar: System.DateTime is a value type, so it can't be null) 

In Whidbey, this is cake using Nullable types:
   public Nullable<DateTime> ShippedDate;
But for now, I've decided to use Object.  Okay choice, I've always thought.  I could use the SqlDateTime which is a refrence type implements INullable but that seems just plain wrong.  I could roll my own reference type, but that wouldn't be good then if I exposed it at the end of a web service.    There's also projects like http://nullabletypes.sourceforge.net/ that I probably should be looking into. But, object was working for me, so I didn't look into it too much. DataGrids and other data bound objects nicely handle the null values, and can also nicely format the dates, if they're not null. 

But, this bit me the other day, when I tried to sort a collection, using the code that I posted in my Sort and Filter Strongly-Typed Collection Classes post.  What happens is that when there's a null value ArrayList.Sort() will throw an exception.

The solution for me turned out to be adding a null equivalent for the actual type that I was trying to sort on. 

    /// <summary>

    /// Gets the null equivalent.

    /// </summary>

    /// <param name="type">Type.</param>

    /// <returns></returns>

    private object GetNullEquivalent(Type type)

    {

      if(type == typeof(System.DateTime)) return DateTime.MinValue;

      if(type == typeof(System.String)) return String.Empty;

      return null;

    }


But, this gets even more complicated, because you don't know the type before hand, so you have to do some looping to find out.   Perhaps there's an attribute that I could use to make this easier, and specify the actual intended type, for stuff like this. Anyhow, because of this, I've had to change the code that does the sorting from this:

    /// <summary>

    /// Does the sort.

    /// </summary>

    private void DoSort()

    {

      sortedList.Clear();

      if (sortBy == null)

      {

        foreach (object obj in BaseList)

        {

          sortedList.Add(new ListItem(obj, obj));

        }

      }

      else

      {

        foreach (object obj in BaseList)

        {

          sortedList.Add(new ListItem(sortBy.GetValue(obj), obj));

        }

      }

      sortedList.Sort();

      isSorted = true;

      if (ListChanged != null)

      {

        ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, 0));

      }

    }


To this:

    /// <summary>

    /// Does the sort.

    /// </summary>

    private void DoSort()

    {

      sortedList.Clear();

      if (sortBy == null)

      {

        foreach (object obj in BaseList)

        {

          sortedList.Add(new ListItem(obj, obj));

        }

      }

      else

      {

 

        System.Type objectType = null;

 

        // Get the type

        foreach (object obj in BaseList)

        {

          object sorter = sortBy.GetValue(obj);

 

          if(sorter != null && objectType == null)

          {

            objectType = sorter.GetType();

          }

          else if(sorter == null && objectType != null)

          {

            sorter = GetNullEquivalent(objectType);

          }

          else if(sorter == null && objectType == null)

          {

            // Loop through, and find the object's type

            foreach(object obj2 in BaseList)

            {

              object sorter2 = sortBy.GetValue(obj2);

 

              if(sorter2 != null)

              {

                objectType = sorter2.GetType();

                break;

              }

            }

 

            // We didn't find the object's type, set it to a string.

            if(objectType == null) objectType = typeof(String);

 

            sorter = GetNullEquivalent(objectType);

          }

 

          sortedList.Add(new ListItem(sorter, obj));

        }

      }

 

      sortedList.Sort();

      isSorted = true;

      if (ListChanged != null)

      {

        ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, 0));

      }

    }


-Brendan


Comments

Brock Allen said:

SqlDateTime is a value type.
# February 16, 2005 3:27 PM

Brendan Tompkins said:

Oops. You're right. It implements INullable. I'll update my post. Embarrassing.
# February 16, 2005 5:40 PM

Brock Allen said:

Heh, ok, now that you've said "I could use the SqlDateTime which implements INullable but that seems just plain wrong", why do you feel that way? They introduced the SqlTypes specifically to allow for the notion of <null> in your code.
# February 16, 2005 6:50 PM

Brendan Tompkins said:

Brock,

The SqlTypes, at least in my mind, allow for a better mapping of actual Sql database types into .NET. Putting these into my entity objects, which I hope and dream will someday be used far away from Sql (at the end of web services, serialized somewhere, populated from web services, etc) is a kludge, sure it works, but not a good use of the sql types, IMO.
# February 17, 2005 5:56 AM

Jørn Schou-Rode said:

I know this blog post is not "active" anymore, but I just want to give tip for anyone finding this from Google or alike.

public Nullable<DateTime> ShippedDate;

can be written more smoothly:

publib DateTime? ShippedDate;

This syntax goes for all Nullable generic types in .NET 2.0.
# May 21, 2006 11:05 AM

Michael Logan said:

Comment above by Jørn Schou-Rode is C# syntax.  This is valid .Net 2.0 VB syntax.

Public dtVarName As Nullable(Of DateTime)

# March 28, 2008 6:47 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Brendan Tompkins

Brendan has been programming with .NET since the first public beta and is owner and operator of Port Technology Services, a consultancy company providing .NET application development services to the Maritime industry. In July, 2007, he was awarded the Microsoft MVP award for ASP.NET. He's also a proud co-founder of failed .COM startup Intrinsigo, and has had a hand in the failure of numerous other businesses. He currently runs CodeBetter.Com and Devlicio.us, and lives in Norfolk, Virgina with his wife Tiara and son Ian.

View Brendan's profile on LinkedIn

Check out Devlicio.us!

Our Sponsors

Free Tech Publications