How to configure Fluent NHibernate automapping so it makes separate hbm for sub classes? - fluent-nhibernate

This question might seems a bit strange at first but there's a legacy project that is working this way and I want to know if there's a way to generate its hbm documents using Fluent Nhibernate.
We have a parent class which is not an abstract class .Something like this:
[Entity("EmployeeTable")]
public class Employee
{
//Memebers of Employee
}
and it has some subclasses.The purpose of these subclasses is merely for code re-usability and as you can see these are some views (Summaries) to represent some information.
[Entity("EmployeeType1View")]
public class EmployeeType1:Employee
{
//Memebers of EmployeeType1
}
[Entity("EmployeeType2View")]
public class EmployeeType2:Employee
{
//Memebers of EmployeeType2
}
So here is the question : is there a way that we can tell fluent nhibernate not to take this inheritance hierarchy into account or in another word to tell it to generate separate hbm file for each of these classes?

unfortunatly FNH can not write subclass maps individually. You could however alter the mapping after writing it to disc.
var model = new FluentNHibernate.Automapping.AutoPersistenceModel();
// add assembly and the like to model
model.WriteMappingsTo(path);
forech(var baseclass in classesWithSubclasses)
{
var doc = new XmlDocument();
doc.Load(baseclass.getType().FullName + ".hbm.xml");
// use xpath to separate the subclassmapping in its own file
}

Related

Fluent nHibernate SubclassMap and AddFromAssemblyOf

I created a generic user repository base class that provides reusable user management functionality.
public class UserRepository<TUser> where TUser : new, IUser
{
}
I have a concrete implementation of IUser called UserImpl, and corresponding mapping class UserImplMap : ClassMap<UserImpl> (they all are in the same namespace and assembly). I add the mapping using AddFromAssemblyOf . I also use this to create / generate the schema.
So far so good and things work as expected.
Now, in a different project, I needed a few additional properties in my IUser implementation class, so I implemented a new class UserImplEx : UserImpl. This class has the additional properties that I needed. Also, I created a new mapping class UserImplExMap : SubclassMap<UserImplEx>
Now when I create schema using this approach, I get two tables one for UserImpl and one for UserImplEx.
Is is possible to configure / code Fluent mapping in some way so that all the properties (self, plus inherited) of UserImplEx get mapped in a single table UserImplEx instead of getting split into two tables?
Alternatively, if I provide full mapping in UserImplExMap : ClassMap<UserImplEx>, then I do get the schema as desired, but I also get an additional table for UserImpl (because corresponding mapping is present in the UserRepository assembly). If I follow this approach, is there a way to tell AddFromAssemblyOf to exclude specific mapping classes?
Option 1
since you have inhertance here and want the correct type back NH has to store the type somewhere, either through the table the data is in or a discriminator.
If a discriminator column in the table does not matter then add DiscriminatorColumn("userType", "user"); in UserImplMap and DiscriminatorValue("userEx") in UserImplExMap
Option 2
class MyTypeSource : ITypeSource
{
private ITypeSource _inner = new AssemblyTypeSource(typeof(UserImplMap).Assembly);
public IEnumerable<Type> GetTypes()
{
return _inner.Where(t => t != typeof(UserImplMap)).Concat(new [] { typeof(UserImplExMap) });
}
public void LogSource(IDiagnosticLogger logger)
{
_inner.LogSource(logger);
}
public string GetIdentifier()
{
return _inner.GetIdentifier();
}
}
and when configuring
.Mappings(m =>
{
var model = new PersistenceModel();
PersistenceModel.AddMappingsFromSource(new MyTypeSource());
m.UsePersistenceModel(model);
})

Fluent NHibernate automapping class conventions aren't being applied to entire class hierarchy

I'm trying to automap a simple inheritance hierarchy with Fluent Nhibernate, and I need to have a slightly different name for each table than its class (underscores instead of Pascal case). This seems like an obvious place to use conventions. I also want to use the table-per-subclass strategy, but the combination seems to be causing me an issue: the convention is only applied to the base class of the hierarchy.
Here's my automapping:
AutoMap
.AssemblyOf<BaseRule>()
.IncludeBase<BaseRule>() // "BaseRule" is an abstract class
.Conventions.Add( DefaultCascade.All() )
.Conventions.Add<OracleTableNameConvention>()
How I want my classes mapped (class name -> table name):
abstract class BaseRule -> Base_Rule
class NumberRule : BaseRule -> Number_Rule
class PatternStringRule : BaseRule -> Pattern_String_Rule
What I'm actually getting:
BaseRule -> Base_Rule
NumberRule -> NumberRule
PatternStringRule -> PatternStringRule
As you can see, only the base class is actually being changed. Here's my existing convention, just so you can see how I'm defining it:
public class OracleTableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
string fixedName = instance.EntityType.Name.ToUnderscoredNaming();
instance.Table(fixedName);
}
}
I've also looked into the ISubclassConvention interface, and can see no way in there to adjust the name of the table (which makes enough sense, subclasses aren't always in their own table).
If I delete the IncludeBase line from my automapping, the names become what I want, except it becomes table-per-concrete-class. I want to use table-per-subclass, leaving all the common data in one shared base table.
I can add overrides for each name, and I will if I have to, but I'd rather not.
It seems like this should be an obviously supported behavior. How can I have the naming convention apply to each table in the hierarchy, without going to table-per-concrete-class?
As soon as I posted this question, I figured it out.
IJoinedSubclassConvention is the interface I needed to implement.
public class OracleSubClassConvention : IJoinedSubclassConvention
{
public void Apply(IJoinedSubclassInstance instance)
{
string fixedName = instance.EntityType.Name.ToUnderscoredNaming();
instance.Table(fixedName);
}
}
I found it by looking for anything that had a method Table(string).

How can I detect NHibernate HasManyToMany mapping at run-time?

I am trying to detect HasManyToMany relationships in entities at run-time for testing purposes. I've had many problems with people writing bad mappings so I wrote a test to test every single mapping on our continuous integration server.
Right now I can test every entity, composite and non-composite by detecting the mapped Id property(s) and calling .Get() or a composite getter. Most of which is done using reflection. I am using GetClassMetadata while going over every entity type.
But I missed testing something that was broken, a HasManyToMany.
I am using Fluent NHibernate, and the mapping is:
mapping.HasManyToMany<ServiceType>(x => x.ServiceTypes)
.Schema("Marketplace")
.Table("ListingServiceTypes")
.ParentKeyColumn("PackageID")
.ChildKeyColumn("ServiceTypeID")
.Cascade.SaveUpdate().LazyLoad();
Now since there is no entity to "test" this relationship with, I do not run over it.
What I need to know is how can I find the properties of an object that are mapped with "HasManyToMany". I can invoke them just fine, if I could only detect them.
I do not want to have to force lazy loading of every collection because if the mapping for the individual entities are correct, the mappings will be, because we use conventions for them.
Get the source code of FluentNHibernate, and copy to your project HasManyToManyStep.cs (FluentNHibernate.Automapping.Steps)
Add your logic to ShouldMap() method. This method is called by FNH to detect Many To Many relations. You can alter the way many to many relations are determined (for example by an attribute). In your case you want probably add a an attribute by reflection to tag the properties...
Replace the default step with your new one :
public class MyMappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
var steps = base.GetMappingSteps(mapper, conventionFinder);
var finalSteps = steps.Where(c => c.GetType() != typeof(FluentNHibernate.Automapping.Steps.HasManyToManyStep)).ToList();
var idx = finalSteps.IndexOf(steps.Where(c => c.GetType() == typeof(PropertyStep)).First());
finalSteps.Insert(idx + 1, new MyCustomHasManyStep(this));
return finalSteps;
}
}
Had to do this today.
var CollectionMetaData = SessionFactory.GetCollectionMetadata(T.FullName + '.' + info.Name);
if (CollectionMetaData is NHibernate.Persister.Collection.BasicCollectionPersister)
{
if (((NHibernate.Persister.Collection.BasicCollectionPersister)CollectionMetaData).IsManyToMany)
{
//Do something.
}
}
where T is the Type and info is the property info from T.GetProperties()

Automatically mapping properties in Fluent NHibernate

I'm taking a complicated legacy schema and mapping it with Fluent NHibernate. The schema is wacky enough that I've given up on automapping; the relationships between tables are weird and complicated, and it would involve a ton of exceptions.
The thing is, the simple properties are totally normal; a table's Title column maps to that entity's Title property, and so on. But because I've opted out of global automapping, there doesn't seem to be a way to avoid mapping each of my string and integer properties on every class. I find myself wanting something like
class SomeMapping : ClassMap<SomeEntity>
{
public SomeMapping()
{
MapEverythingSimple();
}
}
Before I build something complicated that reflectively emits lambda expressions (or somesuch), am I just missing an obvious feature?
How about using automapping and then overrides where things don't fit conventions?
I don't think it's too much of a burden. You'll need to specify the complex relationships
that don't fit a convention somewhere anyhow.
Or you can try NHibernate Mapping Generator to generate NHibernate mapping files and corresponding domain classes from existing DB tables:
http://nmg.codeplex.com/
Use the trial version of Visual NHibernate to quickly generate your entity classes and Fluent mappings, then take it from there. Disclaimer: I work for Slyce Software.
This is not what I ended up doing, but for posterity, here's how you can map properties automatically without using an automapper:
public class PropMap<V> : ClassMap<V>
{
public PropMap()
{
foreach (var propInfo in typeof(V).GetProperties()
.Where(p => simpleTypes.Contains(p.PropertyType)))
{
ParameterExpression param = Expression.Parameter(typeof(V), "x");
Map(Expression.Lambda<Func<V, object>>(
Expression.Convert(Expression.MakeMemberAccess(param, propInfo), typeof(object)), param));
}
}
private static readonly Type[] simpleTypes = new[]
{
typeof (DateTime),
typeof (String),
typeof (int),
typeof (long),
typeof (Enum)
};
}
And then just have the map classes inherit from that. Obviously, it has some serious flaws, and I didn't go with it.

AutoMapping Custom Collections with FluentNHibernate

I am retrofitting a very large application to use NHibernate as it's data access strategy. Everything is going well with AutoMapping. Luckily when the domain layer was built, we used a code generator. The main issue that I am running into now is that every collection is hidden behind a custom class that derives from List<>. For example
public class League
{
public OwnerList owners {get;set;}
}
public class OwnerList : AppList<Owner> { }
public class AppList<T> : List<T> { }
What kind of Convention do I have to write to get this done?
I don't think you're going to be able to achieve this with a convention. You will have to create an auto mapping override and then do the following:
mapping.HasMany(l => a.owners).CollectionType<OwnerList>();