2
votes

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.

2

2 Answers

0
votes
  1. Get the source code of FluentNHibernate, and copy to your project HasManyToManyStep.cs (FluentNHibernate.Automapping.Steps)

  2. 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...

  3. 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; 
        }
    }
    
0
votes

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()