[NHibernate] Automatyczna aktualizacja daty i czasu – o ostatniej zmianie w rekordzie

Jak pisałem poprzednio o problemie braku milisekund w dacie. Wspomniałem o tym, że tabele posiadają kolumnę informującą o ostatniej zmianie, która nastąpiła na rekordzie. Można się domyślić, że ręczne ustawianie tej wartości było by mozolne oraz podatne na błędy ( w szczególności – zapomnienie o wstawieniu nowej wartości)

Można to zautomatyzować przy użyciu Listnera. „Nasłuchiwacza” na zmiany wysyłane do bazy danych.

public class LastChangeListener : IPreUpdateEventListener, IPreInsertEventListener
{
    public bool OnPreUpdate(PreUpdateEvent @event)
    {
        var model = @event.Entity as ILastChange;
        if (model == null)
        {
            return false;
        }

        var time = DateTime.Now;
        Set(@event.Persister, @event.State, "LastChange", time);
        model.LastChange = time;
        return false;
    }

    public bool OnPreInsert(PreInsertEvent @event)
    {
        var model = @event.Entity as ILastChange;
        if (model == null)
        {
            return false;
        }

        var time = DateTime.Now;
        Set(@event.Persister, @event.State, "LastChange", time);
        model.LastChange = time;
        return false;
    }

    private void Set(IEntityPersister persister, object[] state, string propertyName, object value)
    {
        var index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return;
        state[index] = value;
    }
}

Encje posiadają properties (właściwość) o typie DateTime o nazwie LastChange. Do tego te encje implementują interfejs ILastChange, który wymusza zaimplementowanie property LastChange.

Aby NHibernate zaczął korzystać z Listnera, trzeba go zarejestrować podczas tworzenia SessionFactory. Jeżeli korzystasz z Fluent NHibernate rejestracja wygląda następująco:

Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012
.ConnectionString(c => c.FromAppSetting("ConnectionString")))
.ExposeConfiguration(config =>
            {
        config.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[]
        {
            new LastChangeListener(),
        };

        config.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[]
        {
        new LastChangeListener(),
        };
}).BuildSessionFactory();

Źródła