How to handle null when comparing equality objects?

Note. I use C # as an example, but the problem is almost the same in Java and possibly in many other languages.

Suppose you implement a value object (as in the M. Fowler value object template ), and it has a field with a zero value:

class MyValueObject { // Nullable field (with public access to keep the example short): public string MyField; } 

Then, overriding Equals (), how do you feel about the case when both value objects have their MyField set to null? Are they equal or not?

In C #, treating them as equal seems obvious because:

  • This is the behavior of Equals () when you use the C # structure instead of a class and do not override Equals ().

  • The following expressions are available:

     null == null object.ReferenceEquals(null, null) object.Equals(null, null) 

However, in SQL (at least in the SQL Server dialect), NULL = NULL is false, and NULL is NULL is true.

I am wondering what implementation is expected when using O / R mapper (in my case, NHibernate). If you implement the "natural" semantics of C # equality, can there be any negative consequences when O / R matching maps them to the database?

Or perhaps suppose that fields with zero values ​​in value objects are erroneous?

+4
source share
3 answers

Because ORMs know the relational model, they usually provide a query method using SQL semantics.

NHibernate, for example, provides the operator is [not] null in HQL and Restrictions.Is[Not]Null in the criteria.

Of course, there is an API where these paradigms collide: LINQ. Most ORMs try to do the right thing when comparing with zero (i.e., Replacing with is null ), although problems can occur several times, especially if the behavior is not obvious.

+1
source

Personally, I believe that if it can be zero (in the code without errors), then they should be considered equal. However, if it should not be null (i.e.: Name for the Customer or Street address for delivery), then it should never be null.

0
source

I think you have two problems:

One of what you need to know is whether one instance of MyValueObject is equal to another instance.

And secondly, how this should translate into perseverance.

I think you need to look at them separately, because it seems that your angle connects them too close to each other, which seems to me a violation of some DDD principles. The domain does not need to know / care about conservation.

If you are not sure about the effect of the null value of MyField , or (a), it returns a different type than string ; (b) return to it the derived string as EmptyString (or a similar special case ); (c) either override the Equals method and specify exactly what these instances are equal to.

If your ORM cannot translate a specific expression (which includes MyValueObject ) into SQL, then it may normally perform more difficult work at the persistence level (if the comparison comes from an SQL translation - yes, I'm a performance problem, but I'm not sure it is impossible to decide) in favor of maintaining your domain model. It seems that the solution should flow from the β€œbest for domain model”.

@ James Anderson makes a good point. Reserve null for error and failure conditions. I think the Special Case seems more appropriate.

0
source

All Articles