nhibernate configuration patterns
DESCRIPTION
My slides from NHDay conferenceTRANSCRIPT
A simple way to configure NHibernate with a OO approach driven by DI Container
Introduce a “S.O.L.I.D. Design” : a way for abstract configuration responsibility and move it from Strings to Objects.
Introduce a “Plug-In Pattern” : a way to split configuration tasks on several assemblies.
Introduce a “Optionality Pattern” : a way to switch on or off configuration tasks in an opinionated manner (run-time).
Introduce a "Priority Pattern" : a way to sort the execution order of configuration tasks (design-time).
Remember that objects ‘DO’ things. Don’t think about them as “data holders”.
Anticipate changes. Abstract and inject dependency, ALWAYS. Your boss says: “Add new feature…”
Loosely couple as much as you can. Make your application flexible by high cohesion and low coupling.
Always D.R.Y. Avoid cut and paste practice. Do more refactoring. Avoid “FAT” modules.
… and let DI Container glue it together for you!
We have many information (over 40 settings) to provide NHibernate for configure it:
1. Mapping Classes (pick from file, resource, assembly)
2. Database Information (provider, driver, dialect, connection)
3. ProxyFactory (bytecode-provider, reflection-optimizer, etc..)
4. Extension Points (listeners, interceptors)
5. Other Settings (caching, logging, sessionContext, statistics, etc..)
To specify configuration options:
1. Use standard .NET configuration file (web.config o app.config)
2. Use a NHibernate well-know configuration file (called hibernate.cfg.xml)
3. Pass an instance of IDictionary with all settings to Configuration object.
Session FactoryCreator Job
Database Task
Event Listener Task
Mapping Task
Export Schema Task
Dependency Injection Container
execute configuration tasks
IBootstrapperJob
IConfigurationTask<Configuration>
01 /// <summary> 02 /// Associated with an orderable item. 03 /// </summary> 04 public interface IOrderable 05 { 06 int Position{ get;} 07 } 08 09 /// <summary> 10 /// Associated with an bootstrappable item. 11 /// </summary> 12 public interface IBootstrapperJob : IOrderable 13 { 14 void Execute(); 15 } 16 17 /// <summary> 18 /// Associated with an configurable item. 19 /// </summary> 20 public interface IConfigurationTask<T> : IOrderable 21 where T : class 22 { 23 bool CanConfigure(); 24 25 T Configure(T configuration); 26 }
01 /// <summary> 02 /// Job that execute all tasks 03 /// </summary> 04 public class ConfigurationJob : IBootstrapperJob 05 { 06 private readonly IContainer _container; 07 08 public ConfigurationJob(IContainer container) 09 { 10 _container = container; 11 } 12 13 public int Position{ get { return 1; } } 14 15 public void Execute() 16 { 17 var tasks = _container 18 .GetAllInstances<IConfigurationTask<Configuration>>() 19 .OrderBy(x => x.Position); 20 21 var configuration = TaskExecutor.Execute(tasks.ToArray()); 22 23 /*Register Data Component*/ 24 } 25 }
01 /// <summary> 02 /// Map Domain Classes 03 /// </summary> 04 public class DomainMappingTask : FluentTaskBase 05 { 06 public override FluentConfiguration ConfigureCore(FluentConfiguration configuration){ 07 return configuration.Mappings( 08 m => m.FluentMappings 09 .AddFromAssemblyOf<DomainMappingTask>() 10 ); 11 } 12 } 13 /// <summary> 14 /// Configure SqlLite as DataBase 15 /// </summary> 16 public class SqliteDbTask : FluentTaskBase { 17 18 public override bool CanConfigureCore() {return App.NonWeb();} 19 20 public override FluentConfiguration ConfigureCore(FluentConfiguration configuration) 21 { 22 return configuration.Database( 23 SQLiteConfiguration 24 .Standard 25 .UsingFile("test_auditeventlistener.db") 26 .ShowSql()); 27 } 28 }
01 /// <summary> 02 /// Very simple task 03 /// </summary> 04 public class OtherSettingsTask : TaskBase 05 { 06 public override bool CanConfigureCore() 07 { 08 return App.IsWeb(); //is executed only in web env 09 } 10 public override Configuration Configure(Configuration configuration) 11 { 12 configuration.SetProperty(Environment.CurrentSessionContextClass, "web"); 13 14 configuration.SetProperty(Environment.CacheProvider, 15 typeof(HashtableCacheProvider).AssemblyQualifiedName); 16 17 return configuration; 18 } 19 20 public override int Position 21 { 22 get { return 20; } 23 } 24 }
01 /// <summary> 02 /// Execute all task in sequence 03 /// </summary> 04 public static class TaskExecutor 05 { 06 public static TConf Execute<TConf>(Func<TConf> factory, 07 params IConfigurationTask<TConf>[] tasks) 08 where TConf : class, new() 09 { 10 TConf conf = factory(); 11 12 return tasks == null ? conf : 13 tasks.Aggregate(conf, 14 (current, task) => task.CanConfigure() 15 ? task.Configure(current) : current); 16 } 17 }