Alright, so I need to create a couple of tables, which need to be almost identical except for one field.
My model would roughly look like this:
class HouseGeometryModel
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//More fields...
public virtual HouseAttributes Attributes { get; set; }
}
class DungeonGeometryModel
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//More fields, all identical to HouseGeometryModel...
public virtual DungeonAttributes Attributes { get; set; }
}
class FortressGeometryModel
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//More fields, all identical to HouseGeometryModel...
public virtual FortressAttributes Attributes { get; set; }
}
//More models...
So, basically only the Attributes
property differs between all the models here, so I thought there could be a way to unify everything into a single (generic?) class.
I could come up with two ways to implement this:
Make a generic class GeometryModel<TAttributes>
which would look like:
class GeometryModel<TAttributes>
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//More fields...
public virtual TAttributes Attributes { get; set; }
}
The problem with this is that I fail to specify a fluent mapping. The mapping should also become generic this way (to implement ClassMap<GeometryModel<TAttributes>>
) and therefore it would be impossible to instantiate it with NHibernate.
Make the Attributes
property dynamic
. It doesn't work either because NHibernate treats dynamic
properties as object
when creating a ClassMap<>
.
Is there any solution to this?
I ended up doing it generic way with a runtime ClassMap<>
binding.
My model looks like this:
class GeometryModel<TAttributes>
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//More fields...
public virtual TAttributes Attributes { get; set; }
}
My mappings look like this:
class GeometryModelMap<TAttributes> : ClassMap<GeometryModel<TAttributes>>
{
public GeometryModelMap()
{
Id(t => t.Id).GeneratedBy.Increment();
Map(t => t.Name);
//More mappings...
References(t => t.Attributes);
}
}
I wrote the following extension method:
private static FluentMappingsContainer AddGenericMappings(this FluentMappingsContainer container, Type genericType, IEnumerable<Type> genericArgs)
{
foreach (var arg in genericArgs)
{
var newType = genericType.MakeGenericType(arg);
container.Add(newType);
}
return container;
}
And I use it like this:
private static ISessionFactory CreateSessionFactory(string path)
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile(path))
.Mappings(m => m.FluentMappings
.AddFromAssembly(Assembly.GetExecutingAssembly())
.AddGenericMappings(typeof(GeometryModelMap<>), new[] { typeof(HouseAttributes), typeof(DungeonAttributes), typeof(FortressAttributes) } )
)
.ExposeConfiguration(config => BuildSchema(config, path))
.BuildSessionFactory();
}