For some reason, it looks like it is a good day to be impressed by numbers, here it the most interesting one...

And here is the reason you don't want to use the file system as your database:

For some reason, it looks like it is a good day to be impressed by numbers, here it the most interesting one...

And here is the reason you don't want to use the file system as your database:

A while ago I posted how to handle dynamic mapping with Active Record, it was incredibly easy to do, because Active Record has a lot of smarts internally, and output the XML, on top of which NHibernate adds quite a bit of convention over configuration as well. Doing the same using NHibernate directly is possible, but a bit long winded. Here is the sample code, which link all the Employee properties to the correct entity:
Configuration cfg = new Configuration() .AddAssembly(typeof (Employee).Assembly) .AddAssembly(typeof(ScheduledTask).Assembly); Mappings mappings = cfg.CreateMappings(); foreach (PersistentClass persistentClass in mappings.Classes) { if (persistentClass.MappedClass.GetProperty("Employee") == null) continue; Property prop = new Property(); PersistentClass employeeClass = cfg.GetClassMapping(typeof (Employee)); Table table = employeeClass.Table; ManyToOne value = new ManyToOne(table); value.ReferencedEntityName = typeof (Employee).FullName; Column column = new Column("Employee"); value.AddColumn(column); prop.Value = value; prop.Name = "Employee"; prop.PersistentClass = employeeClass; persistentClass.AddProperty(prop); persistentClass.Table.AddColumn(column); persistentClass.Table.CreateForeignKey("FK_EmployeeTo" + persistentClass.MappedClass.Name, new Column[] {column,}, typeof (Employee).FullName); } cfg.BuildSessionFactory(); new SchemaExport(cfg).Execute(true, true, false, true);
As you can see, there is a lot that needs to be done, we have to tell NHibernate a lot of things it would generally be able to figure out on its own. We can shove this to an extension method and get really nice syntax:
public static void MapManyToOne<TEntityInterface, TEntity>(this Configuration cfg) { Mappings mappings = cfg.CreateMappings(); foreach (PersistentClass persistentClass in mappings.Classes) { var propertyNames = new List<string>(); foreach (PropertyInfo property in persistentClass.MappedClass.GetProperties()) { if (property.PropertyType == typeof (TEntityInterface)) { propertyNames.Add(property.Name); } } if (propertyNames.Count == 0) continue; var prop = new Property(); PersistentClass targetClass = cfg.GetClassMapping(typeof (TEntity)); foreach (string propertyName in propertyNames) { Table table = targetClass.Table; var value = new ManyToOne(table); value.ReferencedEntityName = typeof (TEntity).FullName; var column = new Column(propertyName); value.AddColumn(column); prop.Value = value; prop.Name = propertyName; prop.PersistentClass = targetClass; persistentClass.AddProperty(prop); persistentClass.Table.AddColumn(column); string fkName = string.Format("FK_{0}To{1}", propertyName, persistentClass.MappedClass.Name); persistentClass.Table.CreateForeignKey(fkName, new[] {column,}, typeof (TEntity).FullName); } } }
Now we can use this with the following syntax:
cfg.MapManyToOne<IEmployee, Employee>();
Which is much nicer.
It is amazing how much time you can hunt for the exact cause of a bug. In this case, it took me almost two days (intersperse with other work, however) to track down and find the issue.
Remember, there is no reason to use ASCII, ever. I actually run a blame on the code (a new feature for SvnBridge!) to find out who wrote it. And then I sent a nasty email about it to /dev/null, just to clear my mind.
No future posts left, oh my!