Przy korzystaniu z nHibernete’a czasem zachodzi potrzeba, aby prócz tabel, które są mapowane z obiektów mieć jakieś dodatkowe. Ja ostatnio miałem taką potrzebę w związku z Quartz.NET, który ma możliwość przechowywania swoich triggerów i akcji w bazie w przypadku, gdy powinny przeżyć restart puli aplikacji.


tl;dr; Potrzebujesz dodatkowych tabel w bazie mapowanej nHibernate’em użyj AbstractAuxiliaryDatabaseObject, ale nie obejdzie się bez haków.

Oczywiście banalnym rozwiązaniem jest stworzenie dodatkowych tabelek ręcznie w bazie i jest to rozwiązanie jeśli musimy mieć je już i na teraz. Jeśli mamy jednak trochę czasu aby zagłębić się w coś ładniejszego i automatycznego to warto to zrobić.

Jak zapewne wiecie (a jak nie wiecie to już wiecie). Do generowania schematu bazy nHibernate ma dostępne klasy SchemaUpdate oraz SchemaExport, które całkiem ładnie sobie radzą z aktualizacją schematu (Update) i generowaniem go na nowo (Export).

Jak więc do tego wcisnąć dodatkowe tabelki? A no istnieje abstrakcyjna klasa AbstractAuxiliaryDatabaseObject, która jak sama nazwa jej wskazuje reprezentuje dodatkowe obiekty w bazie. Obiektem nie musi być tabela co zaraz zobaczymy. Użycie tego wydaje się być proste implementujemy dwie metody:

    public class QuartzTables : AbstractAuxiliaryDatabaseObject
    {
        public override string SqlCreateString(Dialect dialect, IMapping p,
                                               string defaultCatalog, string defaultSchema)
        {
            return File.ReadAllText(Path.Combine(
                                        AppDomain.CurrentDomain.BaseDirectory,
                                        “SqlScripts/create.sql”));
        }
        public override string SqlDropString(Dialect dialect,
                                             string defaultCatalog, string defaultSchema)
        {
            return File.ReadAllText(Path.Combine(
                                        AppDomain.CurrentDomain.BaseDirectory,
                                        “SqlScripts/drop.sql”));
        }
    }

Metody Create i Drop mogą tworzyć dowolny obiekt bazodanowy. Tak jak już wspomniałem wyżej nie muszą to być tylko tabele.
Następnie dodajemy nasz obiekt do konfiguracji:

configuration.AddAuxiliaryDatabaseObject(new QuartzTables());
new SchemaUpdate(configuration).Execute(null, true, false); 

Gotowe? Niestety nie całkiem. Nie wiem czy tylko ja jestem ślepy czy tej informacji nie ma podanej, ale AddAuxiliaryDatabaseObject nie działa z SchemaUpdate. Trzeba posłużyć się SchemaExport. Nie byłoby w tym nic złego, pomijając to, że Export zawsze tworzy tabele od nowa oczywiście gubiąc dane, które były w tych tabelach zapisane. Na mojej maszynie dev nie jest to problem, ale kod wrzucany jest przez TeamCity na środowisko testowe a tam już dane powinny być.

W rezultacie musiałem stworzyć kod, który na podstawie flagi wykonuje albo Update albo Export. Pół-automatyzacja. Nie idealne rozwiązanie, ale na chwilę obecną może być.

Jeśli znacie lepszy sposób na wybrnięcie z tej sytuacji – piszcie. Strasznie denerwuje mnie obecny kod.