Why we have more than one unique identifier in a table with Sharp Architecture

I was failing to explain to non-OO-aware colleagues about why Sharp Architecture pushes you towards having two unique identifiers on a database table, so I went away, sorted out how to explain Domain Signatures simply in my head, and came up with this explanation. It is hopefully clear, and hopefully correct, so I’ve posted it here to refer back to in future!

There are two reasons:

  1. Ideological: Sharp Architecture is about Domain Driven Design (DDD). A part of DDD is called Persistence Ignorance, the idea is that in order to be usable an entity should not need its database identifier, i.e. you need some way of identifying an object which would work if you were connected to a database or not. This identifier doesn’t need to be another ID code, but you must have a way of uniquely identifying an object (hence the DomainSignature attribute on the property). This allows much easier communication to outside systems too, if necessary, as all systems will know what they are talking about. This article explains it reasonably clearly: http://msdn.microsoft.com/en-us/magazine/dd882510.aspx.
  2. Practical: You cannot easily unit test a method that includes a search for a Sharp Architecture entity that uses Id as the only unique identifier. The Id property is read-only, so you can’t set it in your unit test’s mini ‘database’.

Automatic saving when updating records with SharpArchitecture

Another gotcha for newbie MVC/Sharp programmers (I include myself this time!). As mentioned in a previous post, with SharpArchitecture you need to decorate the method with the [Transaction] attribute in order to save the record you are creating. So far so good. What we hadn’t realised is that you don’t actually need to call the Repository’s SaveOrUpdate() method in order to update an existing record!

If you have a method such as the following in your controller (I am assuming you have created the relevant entity and repository), then this is actually enough to update your ‘RecordType’ database record! Presumably this happens because the transaction is committed once the method is returned. You still need to called SaveOrUpdate() to create new records.

I personally don’t like this feature (I don’t know if it is Sharp or nHibernate) because it is too easy to accidentally update something that shouldn’t be, but once you know it exists then you can look out for it.

[AcceptVerbs(HttpVerbs.Post)]
[Transaction]
public ActionResult Update(MyViewModel model)
{
     RecordType record = _myRepository.GetById(model.Id);
     if (record != null)
     {
           record.Description = model.Description;
      }
}

Reading tables with nHibernate that have SQL keywords as names

With nHibernate, if the name of the table that you are trying to map to happens to have a name which is an SQL Server keyword (i.e. User is a common one), then nHibernate will barf with a syntax error.

The way to get around this in your class map is to do as follows (for a table named User, mapped to a class named User). Notice the square brackets around the table name.

public class UserMap: ClassMap<User>
{
    public UserMap()
    {
        Table("[User]");
        ...
    }
}

If you know much SQL then this might have been obvious, but if not then you’d never get there! Of course you could always just not name your tables with SQL keywords, but if you are developing for legacy systems you may not have a choice…

SELECT DISTINCT with NHibernate

I found a blog post on Stackoverflow about how to do the equivalent of SQL’s SELECT DISTINCT in nHibernate, but I can’t seem to find it again so here is what I got from it. Thanks to whoever it was on that site!

To return a list of the distinct combination of two columns (MyColumn1 and MyColumn2) from a table MyTable do the following within your custom repository (I’m assuming that you’ve already created the MyTable class, IMyTable interface and appropriate class map of course!:

public IList<IMyTable> GetAllDistinctCombinations()
{
            NHibernate.ICriteria criteria = Session.CreateCriteria(typeof(IMyTable));

            criteria.SetProjection(
                    Projections.Distinct(Projections.ProjectionList()
                        .Add(Projections.Alias(Projections.Property("MyColumn1"), "MyColumn1"))
                        .Add(Projections.Alias(Projections.Property("MyColumn2"), "MyColumn2"))
                           ));

            criteria.SetResultTransformer(
                    new NHibernate.Transform.AliasToBeanResultTransformer(typeof(MyTable)));



            return criteria.List<IMyTable>();
}

Note that although this returns a list of MyTable objects, only the properties that correspond to MyColumn1 and MyColumn2 will be populated on each object.

Using different web.config/NHibernate.config settings for each Visual Studio release configuration

When you have a development, test and production environment it is likely that each one has different connection strings and other application settings. To avoid the tedium (and any errors) of having to manually change the config files each time you change configuration then I suggest Scott Hanselmann’s method of using a pre-build command that chooses one out of multiple config files (one for each configuration) is a less error-prone way of doing it.

His article is here.

There are several other things to note here:

  1. The pre-build command is not quite correct (for my system anyway). Instead of:
    "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    

    You will need:

    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    
  2. If you are using NHibernate then you will probably also want to change the NHibernate.config file between releases. In which case simply add another line to the pre-build event:
    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)NHibernate.config.$(ConfigurationName)" "$(ProjectDir)NHibernate.config"
    
  3. If you are using SourceSafe then you will need to make sure that your Web.config and NHibernate.config files are checked out prior to building, otherwise they are read-only and the copy process won’t be able to overwrite them (and you probably wouldn’t want it to anyway).
  4. Of course any new application settings etc probably have to be added into all versions of the config files, rather than just the one.

This method saves a lot of mistakes being made in more complex web.config files.

Locking a record using nHibernate

If you are generating your own reference number, or updating a stock level, or anything that means that you need to make sure that only one person at a time can access that record then you need to lock it.

You can do this in nHibernate with the following example code in your repository; the SetLockMode addition is the key method:

using NHibernate;
/// <summary>
/// Set the specified key in a config table to the specified value
/// </summary>
/// <param name="keyName">Name</param>
/// <param name="keyValue">Value</param>
public void SetKeyValue(string keyName, string keyValue)
{
     NHibernate.ICriteria criteria = Session.CreateCriteria(typeof(MyConfig))
                .Add(Expression.Eq("KeyName", keyName)
                 ).SetLockMode(LockMode.Upgrade);

     MyConfig newConfig = criteria.UniqueResult() as MyConfig;

     newConfig.KeyValue = keyValue;
     SaveOrUpdate(newConfig);
 }

Note that this record is only locked once the process passes the UniqueResult() method, i.e. at the point it returns a value to the program. It is unlocked once the wrapping transaction is committed or rolled back, so if your value is something that needs updating many times a second I recommend trying to minimise the size of that transaction!

nHibernate SaveOrUpdate() not working

nHibernate’s SaveOrUpdate() repository function only works within a transaction! Obvious when you think about it, but how you actually create the transaction with Sharp Architecture in the first place isn’t!

Within your MVC controller class file you need to import the following:

using SharpArch.Web.NHibernate;

Then add the [Transaction] attribute to the controller method that contains the transaction:

[HttpPost]
[Transaction]
public ActionResult Wibble(ViewModel thisView)
{
           ...
}

That’s it. The transaction is committed once the method returns. If you want to rollback (perhaps after catching an exception), then call:

catch (Exception ex)
{
            _myRepository.DbContext.RollbackTransaction();
}

You can also add the [Transaction] attribute to the class itself, in which case every method of the class becomes a transaction.