# Tuesday, 23 January 2007

I've started work on the search piece of our application.  Searching (no pun intended) for some inspiration on how users might want to search within our application, I brought up the current WinForms version, and then the ASP.NET version.

I realized that we need to make searching easier in WinForms client, currently when searching for a patient in our WinForms client, you are presented with a separate text box for first name, last name, SSN, date of birth, and health record number.  Our ASP.NET client presents just one text box to search all of those fields.

Tying the Domain Model to the Data Access Layer

So I started thinking about all the pieces in our domain model that we might want to allow the user to search.  Then I realized that to allow searching across all the fields in an entity would tie the data access layer (DAL) to  the domain model ala something like this:

public IList<Patient> Search(string text) { ICriteria criteria = session.CreateCriteria(typeof(Patient)); Disjunction or = Expression.Disjunction(); text = string.Format("%{0}%", text); or.Add(Expression.Like("FirstName", text)); or.Add(Expression.Like("MiddleName", text)); or.Add(Expression.Like("LastName", text)); crit.Add(or); return criteria.List<Patient>(); }

Variations of this code would have to be repeated for every data access class in our DAL.  You could create a string list of the properties on the entity to search and pass them to a method that would build your criteria; but at the end of the day, your still tying your domain model to your data access layer.

Custom Attributes

I started doing some thinking about how unit testing frameworks such as  work and realized I could use .NET custom attributes and some reflection to solve the problem.

I came up with an attribute called Search, currently it takes in one boolean parameter called Enabled.

1 using System; 2 using System.Reflection; 3 4 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 5 public class SearchAttribute : System.Attribute 6 { 7 public bool Enabled; 8 9 /// <summary></summary> 10 /// </summary> 11 /// <param name="Enabled">if true, property will be included in object-level searches</param> 12 public SearchAttribute(bool Enabled) 13 { 14 this.Enabled = Enabled; 15 } 16 }

I could have written it as:

1 using System; 2 using System.Reflection; 3 4 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 5 public class SearchAttribute : System.Attribute { }

But I wanted the flexability of adding named parameters in the future.  Who knows, maybe this is a lame reason, and I should just refactor the code if I want to add parameters to it in the future.

Adding the Attribute to Your Domain Model

The interesting thing about a custom attribute, is if it ends in Attribute (i.e. SearchAttribute), its name gets changed to Search by the C# compiler(?), although you could still use SearchAttribute as the name when you add it to your properties.  If you look at the IL, its still called SearchAttribute:

.custom instance void MyNamespace.SearchAttribute::.ctor(bool) = ( bool(true) )

But if you change the attribute name to SearchAttrib, or SearchAttributes, then you have to use the full name when decorating the properties in your class.  This really isn't germane to the topic at hand, I just thought it was neat! :)

Example:

1 public class Patient 2 { 3 [Search(true)] 4 public string FirstName 5 { 6 get { return _firstName; } 7 set { _firstName = value; } 8 } 9 ... 10 }

Pulling it All Together

The custom attribute is great and all, but it doesn't inherently buy us anything.  We need to add a little bit more to make all this work.  This is a simplified version of what I ended up putting in my DAL base class:

1 private IList<Patient> Search(string text) 2 { 3 Type type = typeof(Patient); 4 ICriteria criteria = _session.CreateCriteria(type); 5 6 Disjunction or = Expression.Disjunction(); 7 foreach (PropertyInfo propInfo in type.GetProperties()) 8 { 9 //SearchableAttribute is AllowMultiple = false, so we only need the first item 10 Attribute[] attribs = Attribute.GetCustomAttributes(propInfo, typeof(SearchAttribute)); 11 if (attribs.Length == 0) 12 continue; 13 14 if (((SearchAttribute)attribs[0]).Enabled) 15 or.Add(Expression.InsensitiveLike(propInfo.Name, string.Format("%{0}%", text))); 16 } 17 criteria.Add(or); 18 return criteria.List<T>(); 19 } 20

Again, this is a simplified version of what's in our DAL base class, the actual signature looks more like this: private IList<T> Search<T>(string text) so that I don't have to write a version of this for each class in our domain model I want to enable searching for.

Everything above should be pretty self-explanatory unless you aren't familiar with the NHibernate Criteria API; in which case the Expression.Disjunction bit on line 6 is how you do an OR (a OR b OR c)when searching.  You can also do Expression.Conjunction if you want AND searching (a AND b AND c).

The original version of this code had a second foreach loop which spun through all the attributes on each property looking for the SearchAttribute.  I thought to myself that their had to be a better way and did a little bit of poking around, and discovered much to my delight that the static method Attribute.GetCustomAttributes allows you to specify what kind of attribute you are searching for!

Limitations

In the code above, you'll get an Exception if you try to search against non-text columns in your database so you will need to that into account when putting the Search attribute in your Domain Model; or add some more smarts to the Search method to take into account different data types.

Comments

If you've read down this far, then I'd love to get a comment from you.  Is there anything you think I could do a better job of explaining, am I an awesome guy?  Or do I suck, either way, I'd like to know, so please leave me a comment!

If you like my article, please kick it at .NET Kicks (I have no idea why the kick counter says I have zero kicks btw)!

.NET | C# | NHibernate | ORM | Searching
Tuesday, 23 January 2007 11:02:42 (Alaskan Standard Time, UTC-09:00)
# Thursday, 18 January 2007

We are in the midst of doing a total rewrite of our Software, and one of the things that has come up is date and time.  How do we do it, how do we store it, and how do we ensure that we can compare DateTime from one timezone to DateTime in another timezone.  After a lot of research, we settled on using UTC (or UCT depending on your preference).  FxCop will take care of ensuring we use UTC (for the most part).

That solves the problem, or so we thought.  Turns out, when you create a DateTime object either through the constructor, or through DateTime.Parse, its Kind defaults to DateTimeKind.Unspecified.  We need a way to ensure that all DateTime objects are always set to UTC.

What are our options?

Because we are using NHibernate, we have a few options.  The three NHibernate specific ones that immediately come to mind are using an Interceptor, a custom UserType with a SQL datetime column, and a custom UserType with a SQL varchar column; and the non-NHibernate specific one is creating our own DateTime container.  What are the pros and cons of each of these?

NHibernate Interceptor

Pro: very cross-cutting, can touch every object as it comes in and goes out to the database; if there are other data types we need to monkey with, we already have a framework in place.

Con: Very cross-cutting, can be expensive because it's touching every property on every entity as the entities are loaded and persisted

UserType with SQL datetime column

Pro: Only touching the DateTime objects that we want it to

Con: The type has to be specified for every DateTime object in every mapping file; no meta-data along with the date to stamp in the timezone it was created in

UserType with SQL varchar column

Pro: Only touching the DateTime objects that we want it to; can store the timezone and offset along with the date in the db

Con: Same as above UserType; abusing SQL data types; datetimes created at the same (relative) time in two different timezones won't be sorted correctly

Custom DateTime container

Pro: We can do anything we want

Con: Yuck! - I could write a whole paragraph on why this is yucky, but I'll leave that to your imagination

 

After some thought, I decided on the Interceptor!  Here is the class I came up with (you can also download the complete UtcDateTimeInterceptor class):

1 class UtcDateTimeInterceptor : IInterceptor 2 { 3 public bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types) 4 { 5 ConvertDatabaseDateTimeToUtc(state, types); 6 return true; 7 } 8 9 public bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types) 10 { 11 ConvertLocalDateToUtc(state, types); 12 return true; 13 } 14 15 public bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, 16 IType[] types) 17 { 18 ConvertLocalDateToUtc(currentState, types); 19 return true; 20 } 21 22 private void ConvertLocalDateToUtc(object[] state, IType[] types) 23 { 24 int index = 0; 25 foreach (IType type in types) 26 { 27 if ((type.ReturnedClass == typeof(DateTime)) && state[index] != null && (((DateTime)state[index]).Kind == DateTimeKind.Utc)) 28 { 29 state[index] = ((DateTime)state[index]).ToUniversalTime(); 30 } 31 32 ++index; 33 } 34 } 35 36 private void ConvertDatabaseDateTimeToUtc(object[] state, IType[] types) 37 { 38 int index = 0; 39 foreach (IType type in types) 40 { 41 if ((type.ReturnedClass == typeof(DateTime)) && state[index] != null && (((DateTime)state[index]).Kind == DateTimeKind.Unspecified)) 42 { 43 //Create a new date and assume the value stored in the database is Utc 44 DateTime cur = (DateTime)state[index]; 45 DateTime result = DateTime.SpecifyKind(cur, DateTimeKind.Local); 46 state[index] = result; 47 } 48 49 ++index; 50 } 51 } 52 }

Loading The Entities

For the sake of brevity, I'm going to exclude the bits of the Interceptor interface that aren't relevant to my posting.  With that said, the OnLoad event (line 3) gets fired every time an entity is loaded from the database.  We can count on the fact that all dates are stored as UTC in the database because of stuff we'll do later, so we need to convert the DateTime that NHibernate generates (which has a DateTimeKind of Unspecified) to a UTC date (line 36 - 48).  The types array holds the CLR data type of each property in the entity, and each type in the array contains both the internal NHibernate type, and the CLR type. But we don't really care about how NHibernate maps the data types internally, so we are only interested in type.ReturnedClass.

The first thing we need to do is see if the ReturnedClass is of type DateTime (line 41), if its a DateTime, then we need to see if its null, and finally double check that the Kind on the DateTime object coming back from the database is Unspecified.  This last check is a sanity check, in case this behavior changes in the future.

After all these checks are passed, we need to create a new DateTime object from the old one, and set its Kind to Utc (lines 44 and 45).  Thankfully, DateTime has the built-in method SpecifyKind which will take care of building a DateTime of the specified kind for us. And finally replace the existing DateTime object with our new one (line 46).  Shampoo, rinse, repeat for all the DateTime values in the entity.

Persisting The Entities

Now we can move on to the save and update NHibernate events (line 9, and 15 respectively).  In these, we want to make sure the values being persisted to the datastore are UTC, and that no Local times have slipped through the cracks.  If one were so inclined, they could throw an error instead of converting the DateTime to UTC...

The basic code for converting Local DateTime's to Utc (line 22- 34) is much the same as above, but with a few exceptions.  When we do all our checks (line 27), this time we make sure the DateTimeKind is Local before we perform a conversion operation on it.  It is pointless to check if the Kind is Unspecified, because there is no conversion operation we can really perform on it.  On line 29, we can use the built in DateTime method ToUniversalTime() to convert a LocalTime to UTC.

Finishing Up

How do we wire this all up?  When you open a session on your session factory, you can pass in an Interceptor, this is where you would pass in the UtcDateTimeInterceptor.  eg:

ISession openSession = ourSessionFactory.OpenSession(new UtcDateTimeInterceptor());

I want to give credit where credit is due, I got the actual idea of using an Interceptor from  where he grappled with DateTime, null, messages and web services.  If anyone using NHibernate doesn't read , I would highly encourage you to.  He is a very, very sharp fellow; and prolific blogger.

.NET | C# | NHibernate | ORM
Thursday, 18 January 2007 15:36:52 (Alaskan Standard Time, UTC-09:00)
# Saturday, 30 December 2006

Often times when you're developing an application, there is a one-to-one mapping between your domain model (object model) and your database schema.  Doing it this way often times makes it easier to wrap your head around everything going on in your app.

 

But this isn’t always the right way to do things.  For example, take the highlighted columns in the UserCredential table:


 

In the UserCredential class, do you really want to have HashedPassword, HashType, and PasswordSalt properties?  Probably not...  So, how can we still do our mapping with NHibernate and avoid creating a clunky UserCredential class?  Enter NHibernates CompositeUserTypes!

 

First, let’s create our domain objects:

Notice that the UserCredential class contains a property called Password, which maps to the class Password.

 

Now, let’s create our CompositeUserType, in our case, we’ll call it PasswordCompositeUserType, and this class will implement the NHibernate.IUserType interface:

public class PasswordCompositeUserType : IUserType { public new bool Equals(object x, object y) { if (x == y) return true; if (x == null || y == null) return false; return x.Equals(y); } public object DeepCopy(object value) { if (value == null) return null; else return ((Password)value).Copy(); } public int GetHashCode(object x) { return x.GetHashCode(); } public bool IsMutable { get { return false; } } public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) { if (rs.IsDBNull(rs.GetOrdinal(names[0])) || rs.GetOrdinal(names[0]) == string.Empty) return null; string hashedPassword = (string)rs[names[0]]; long salt = (long)rs[names[1]]; HashType hashType = (HashType)Enum.Parse(typeof(HashType), (string)rs[names[2]]); Password result = new Password(); result.HashedPassword = hashedPassword; result.Salt = salt; result.HashType = (HashType)Enum.Parse(typeof(HashType), hashType); return result; } public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index) { if (value == null) { ((IDataParameter)cmd.Parameters[index]).Value = null; ((IDataParameter)cmd.Parameters[index + 1]).Value = null; ((IDataParameter)cmd.Parameters[index + 2]).Value = null; } else { Password pass = (Password)value; ((IDataParameter)cmd.Parameters[index]).Value = pass.HashedPassword; ((IDataParameter)cmd.Parameters[index + 1]).Value = pass.Salt; ((IDataParameter)cmd.Parameters[index + 2]).Value = pass.HashType; } } public Type ReturnedType { get { return typeof(Password); } } public global::NHibernate.SqlTypes.SqlType[] SqlTypes { get { global::NHibernate.SqlTypes.SqlType[] types = new global::NHibernate.SqlTypes.SqlType[3]; types[0] = new global::NHibernate.SqlTypes.SqlType(DbType.String); types[1] = new global::NHibernate.SqlTypes.SqlType(DbType.Int64); types[2] = new global::NHibernate.SqlTypes.SqlType(DbType.String); return types; } } }

Looks complicated, but it’s not.  Let’s break it down method by method.

public new bool Equals(object x, object y) – Returns whether object x and y are equal.  Why does it matter?  In our case, it really doesn’t (that I’m aware of); but NHibernate uses this to figure out the relationship between objects in your domain model.

public object DeepCopy(object value) – Creates a deep copy, I’m not sure why NHibernate needs this.  Note, in my implimentation of Password, I created a Copy method.  You could also create a new Password object, set the properties of that new object, and return that as well.  Something like this:

Password p = (Password)value;

Password result = new Password();

result.HashedPassword = p.HashedPassword;

result.HashType = p.HashType;

result.Salt = p.Salt;

return result;

 

I don’t know about you, but I prefer to encapsulate all this into the object itself :).

public int GetHashCode(object x) - Returns the hashcode for the object.

public bool IsMutable – Is this object mutable?  In our case, it doesn’t matter so we return false.

public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) – This is where a lot of the magic happens :) First thing to do is check if the value from the database is null or empty, if it is, then we can return null and be done.  Second step, grab all the values from the data reader.

This is one of the things I don’t like about NHibernate, you have to get the values out by ordinal value.  Not only by the ordinal value, by in the same order they are mapped in the NHibernate mapping file (more on this later).  And finally, build and return a Password object.

public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index) – This is the other half of the magic :) This code is fairly straight forward so I won’t bother to explain it.

public Type ReturnedType – Tells NHibernate what type of object will be returned by this CompositeUserType.

public global::NHibernate.SqlTypes.SqlType[] SqlTypes – Tells NHibernate what data types of each column is.  Again, the the columns are in ordinal order.  Why “the global::” you might ask?  Well, we have a class called NHibernate in our DataAccessLayer, so the global:: bit tells the C# compiler to backup and look in the global NHibernate namespace.  If you don’t have this issue, you can get rid of the global:: part.

 

Now, onto the Hibernate mapping file:

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class name="MyNamespace.DomainModel.UserCredential, MyNamespace.DomainModel" table="UserCredential" lazy="false"> <id name="Id" column="ID" type="Guid"> <generator class="guid.comb"/> </id> ... <property name="Password" type="MyNamespace.DataAccess.PasswordCompositeUserType, MyNamespace.DataAccess" > <column name="HashedPassword"/> <column name="Salt"/> <column name="HashType"/> </property> <property name="IsActive" /> </class> </hibernate-mapping>

Notice that the column order in the mapping file for our CompositeUserType in our mapping file is in the exact same order as in our PasswordCompositeUserType class.

 

I know this post was very long, but hopefully you found it useful and can adapt it to meet your specific needs!  Next up, using a NHibernate UserType to map the .NET IPAddress class to/from your database.


Questions, comments, please feel free to leave a comment.  This is my first article and I'd like as much feedback as possible!

Saturday, 30 December 2006 23:58:24 (Alaskan Standard Time, UTC-09:00)
# Thursday, 28 December 2006
 #
 

This is the first post of my new (mostly) technology related blog.  In the coming days I plan on posting a few articles on NHibernate.  More specificly on how to create custom UserTypes and CompositeUserTypes.  In the mean time, my co-worker posted an article last week on a generic enum mapper for NHibernate.

Thursday, 28 December 2006 19:54:46 (Alaskan Standard Time, UTC-09:00)