Here's the final approach that I took to organize my overrides:
1) Add an override interface to your application as follows:
using FluentNHibernate.AutoMap;
namespace SharpArch.Data.NHibernate.FluentNHibernate
{
/// <summary>
/// Used by <see cref="AutoPersistenceModelExtensions" /> to add
auto mapping overrides
/// to <see cref="AutoPersistenceModel" />
/// </summary>
public interface IAutoPeristenceModelConventionOverride
{
AutoPersistenceModel Override(AutoPersistenceModel model);
}
}
2) Create an extension method, as follows, to look for every class
which implements IAutoPeristenceModelConventionOverride, in a
particular assembly, and apply the override to AutoPersistenceModel:
using FluentNHibernate.AutoMap;
using System.Reflection;
using System;
using SharpArch.Core;
namespace SharpArch.Data.NHibernate.FluentNHibernate
{
/// <summary>
/// Provides a means to override <see cref="AutoPersistenceModel" /
> conventions with classes
/// that implement <see
cref="IAutoPeristenceModelConventionOverride" />.
/// </summary>
public static class AutoPersistenceModelExtensions
{
public static AutoPersistenceModel
MapConventionOverridesFromAssemblyOf<TOverride>(
this AutoPersistenceModel autoPersistenceModel) where
TOverride : IAutoPeristenceModelConventionOverride {
Assembly assemblyToPullConventionOverridesFrom = typeof
(TOverride).Assembly;
foreach (Type type in
assemblyToPullConventionOverridesFrom.GetTypes()) {
if (typeof
(IAutoPeristenceModelConventionOverride).IsAssignableFrom(type)) {
IAutoPeristenceModelConventionOverride instance =
Activator.CreateInstance(type) as
IAutoPeristenceModelConventionOverride;
if (instance != null)
instance.Override(autoPersistenceModel);
}
}
return autoPersistenceModel;
}
}
}
3) Create a class for each entity that requires a convention override;
for example:
using FluentNHibernate.AutoMap;
using Northwind.Core;
using SharpArch.Data.NHibernate.FluentNHibernate;
namespace Northwind.Data.NHibernateMappings
{
public class CustomerMap : IAutoPeristenceModelConventionOverride
{
public AutoPersistenceModel Override(AutoPersistenceModel
model) {
return model.ForTypesThatDeriveFrom<Customer>(map => {
map.SetAttribute("lazy", "false");
});
}
}
}
4) Include a call to the extension method when setting up the
AutoPersistenceModel; e.g.,
AutoPersistenceModel mappings = AutoPersistenceModel
.MapEntitiesFromAssemblyOf<Customer>()
...
.WithConvention(GetConventions)
.MapConventionOverridesFromAssemblyOf<CustomerMap>();
I'll be including this approach in the next release of S#arp
Architecture which leverages Fluent NHibernate. Hope this helps!
Billy McCafferty
On Feb 9, 9:03 am, Steven Harman <[email protected]> wrote:
> Being one of the folks currently using the AutoPersistenceModel in an
> unconventional (or rather, just unexpected) manner, I suppose I should speak
> up in favor of allowing, and suggesting, that class-specific convention
> overrides be split out into their own auto mappings files. I'm on board
> w/Andy - this approach keeps things more granular, better seperated, and
> easier to grok when you have a large number of mappings.
>
> That said, I also see James concern that it might not be obvious that these
> small one-off maps are actually overriding some other auto mapping, setup
> elsewhere. However, I think some smart naming conventions, namespacing, and
> a little bit of education could go a long way toward eliminating that
> concern. But then, that's just my opinion.
>
> Perhaps talking about the various ways folks are using FNH mappings (both
> auto and manual), and the lessons we're learning, would be a good topic for
> a VAN Meeting?
>
> -steve
>
> //---- 90% of being smart is knowing what you're dumb at
> ----//http://stevenharman.net/
>
> On Mon, Feb 9, 2009 at 9:44 AM, AndyStewart <[email protected]>wrote:
>
>
>
> > Hi James
>
> > I've not read the whole thread, so forgive me if I'm going in the
> > wrong direction. However let me shed some light on this,
> > looks like some users of the library are inheriting from AutoMap and
> > using the model.addMappingsFromAssembly( ); method.
> > This is in-fact the very first way I wrote automappings, until Chad
> > showed me the light to the fluent method. However if
> > your doing alot of custom mappins then loading in via seperate classes
> > is a lot cleaner than the 80 lins of fluent code
> > I have in one of my projects (yuk).
>
> > Hope you this puts you in the picture as how this has come about.
>
> > Andy
>
> > On Feb 9, 10:33 am, James Gregory <[email protected]> wrote:
> > > Billy, it's important to note that I never said you shouldn't be deriving
> > > from AutoMap<T>. If that works for you (or did...) then great. My point
> > is
> > > that this style of modeling has evolved without my knowledge, which is
> > > interesting and concerning at the same time; if it's a good thing then I
> > > have no issue with it, but I can't be seen to endorse it without
> > > understanding the implications of it's use beforehand.
> > > For starters, we have no tests covering this code; which leads us to
> > > situations like this where I manage to break it for people without ever
> > > knowing. We have no examples promoting this style (unless somebody's
> > written
> > > some I wasn't aware of), and as a result we have no way of supporting
> > this
> > > from a guidance perspective.
>
> > > My final disagreement with this is that I don't actually like the way it
> > > feels. It looks like a ClassMap, smells like a ClassMap, but is an
> > AutoMap.
> > > You look at it and, unless you already know that it's an AutoMap, think
> > > "where are all the other mappings?" However, that could just be me
> > because
> > > I'd not used it in this manner.
>
> > > All that being said, I can definitely see the merit in separating the
> > > overrides into their own classes. People obviously like doing overrides
> > in
> > > the manner that #arch does them, so presuming I can get the code under
> > test
> > > (and fix the bug), I have no issue with people proceeding.
>
> > > I've got some time tomorrow working on FNH, so I'll take a look at this
> > > then.
>
> > > On Mon, Feb 9, 2009 at 3:16 AM, Billy <[email protected]> wrote:
>
> > > > I was also inheriting from AutoMap and ran into the same exception
> > > > with recent updates. The workaround that I've put in place for this
> > > > issue for keeping overrides well organized is described at
>
> > > >http://groups.google.com/group/sharp-architecture/msg/c74d493fc74ed98.
> > ..
> > > > .
> > > > Although it's within the context of S#arp Architecture, it could be
> > > > reused in any project.
>
> > > > Billy McCafferty
>
> > > > On Feb 3, 12:13 pm, Jimit <[email protected]> wrote:
> > > > > The method MergeWithAutoMapsFromAssembly<T>() seemed to suggest the
> > > > > style I used - that is, subclassing AutoMap<T> in an assembly. It did
> > > > > discover my automaps fine, but then failed with the error described.
> > > > > My domain has some very deep hierarchies and the fluent configuration
> > > > > (using ForTypesThatDeriveFrom<T>) was getting rather wordy so I
> > > > > seperated them into individual subclasses of AutoMap<T> and merged
> > > > > them into my AutoPersistenceModel using
> > > > > MergeWithAutoMapsFromAssembly<T>(). It seemed to work fine, until it
> > > > > didn't. :) I think subclassing AutoMap<T> should be supported, if
> > > > > nothing else than for consistency with ClassMap<T> for non-automapped
> > > > > entities.
>
> > > > > Speaking of ForTypesThatDeriveFrom<T>, I think a non-generic overload
> > > > > might come in handy. One use case (that's got me stumped at the
> > moment
> > > > > - having to use reflection) is setting conventions for the open form
> > > > > of a generic base type, e.g EntityBase<,>. In my particular case, I
> > > > > want to ignore certain properties in EntityBase<TEntity,TId> but
> > don't
> > > > > want to have to tell the Automapper to ignore it for each individual
> > > > > TEntity. Any suggestions?
> > > > > On a side note, you mentioned a check-in adding support for mapping
> > > > > generic base classes
>
> > > > > On Feb 3, 4:32 pm, James Gregory <[email protected]> wrote:
>
> > > > > > Hi,
> > > > > > You seem to be correct in your analysis. The reason this is
> > happening
> > > > is
> > > > > > because it was never intended that people would subclass
> > AutoMap<T>;
> > > > > > alterations to classes are supposed to be done in the
> > > > > > ForTypesThatDeriveFrom<T> call on the automapper, rather than in a
> > > > subclass.
>
> > > > > > I realise this is probably quite annoying, but I'm not willing to
> > > > endorse
> > > > > > this style of automapping until I've done some investigation into
> > it's
> > > > > > implications. For the time being, I'd recommend either altering
> > your
> > > > code to
> > > > > > use the recommended ForTypesThatDeriveFrom call, or altering the
> > code
> > > > > > yourself.
>
> > > > > > I will make a note to review this style to see if it's something we
> > > > should
> > > > > > officially support.
>
> > > > > > James
>
> > > > > > On Tue, Feb 3, 2009 at 4:25 PM, Jimit <[email protected]>
> > wrote:
>
> > > > > > > Hi,
> > > > > > > Sorry if this comes as a duplicate post. I think google might
> > have
> > > > > > > eaten my first so here it is again.
> > > > > > > First off, mad props to all of you involved in the FNH - it
> > rocks!
> > > > > > > That said, I've come across what seems to be abugin the method
> > > > > > > FindMapping<T> of the AutoPersistenceModel class. Here's a sample
> > > > > > > stack trace:
>
> > > > > > > TestCase 'Can_Write_XML_Mapping_Metadata_To_Folder'
> > > > > > > failed: System.Reflection.TargetInvocationException : Exception
> > has
> > > > > > > been thrown by the target of an invocation.
> > > > > > > ----> System.IndexOutOfRangeException : Index was outside the
> > bounds
> > > > > > > of the array.
> > > > > > > at System.RuntimeMethodHandle._InvokeMethodFast(Object
> > target,
> > > > > > > Object
> > > > > > > [] arguments, SignatureStruct& sig, MethodAttributes
> > > > methodAttributes,
> > > > > > > RuntimeTypeHandle typeOwner)
> > > > > > > at System.RuntimeMethodHandle.InvokeMethodFast(Object
> > target,
> > > > Object
> > > > > > > [] arguments, Signature sig, MethodAttributes methodAttributes,
> > > > > > > RuntimeTypeHandle typeOwner)
> > > > > > > at System.Reflection.RuntimeMethodInfo.Invoke(Object obj,
> > > > > > > BindingFlags invokeAttr, Binder binder, Object[] parameters,
> > > > > > > CultureInfo culture, Boolean skipVisibilityChecks)
> > > > > > > at System.Reflection.RuntimeMethodInfo.Invoke(Object obj,
> > > > > > > BindingFlags invokeAttr, Binder binder, Object[] parameters,
> > > > > > > CultureInfo culture)
> > > > > > > at System.Reflection.MethodBase.Invoke(Object obj,
> > Object[]
> > > > > > > parameters)
> > > > > > > at
>
> > FluentNHibernate.InvocationHelper.InvokeGenericMethodWithDynamicTypeArgumen
> > > > ts
> > > > > > > [T](T target, Expression`1 expression, Object[] methodArguments,
> > Type
> > > > > > > [] typeArguments)
> > > > > > > at
> > > > FluentNHibernate.AutoMap.AutoPersistenceModel.FindMapping(Type
> > > > > > > type)
> > > > > > > at
> > > > FluentNHibernate.AutoMap.AutoPersistenceModel.CompileMappings()
> > > > > > > C:\Projects\Dev\Source\Core\Tests\Unit Tests
> > > > > > > \Core.Infrastructure.Data.NHibernate.Tests\MappingTests.cs(47,0):
> > at
>
> > Core.Infrastructure.Data.NHibernate.Tests.MappingTests.Can_Write_XML_Mappin
> > > > g_Metadata_To_Folder
> > > > > > > ()
> > > > > > > --IndexOutOfRangeException
> > > > > > > at
>
> > FluentNHibernate.AutoMap.AutoPersistenceModel.<FindMapping>b__7[T]
> > > > > > > (IMapping t)
> > > > > > > at System.Collections.Generic.List`1.Find(Predicate`1
> > match)
> > > > > > > at
> > > > FluentNHibernate.AutoMap.AutoPersistenceModel.FindMapping[T]()
>
> > > > > > > The test above simply instantiates a new AutoPersistenceModel,
> > calls
> > > > > > > MergeWithMappingsFromAssembly<T>() to add some custom mappings
> > > > > > > (classes inheriting from Automap<T>), calls CompileMappings() and
> > > > > > > attempts to write them to a folder using WriteMappingsTo().
>
> > > > > > > I believe the culprit is this line in FindMapping<T>:
>
> > > > > > > // standard AutoMap<T> not found for the type, so
> > looking
> > > > > > > for one for it's base type.
> > > > > > > return (IClassMap)_mappings.Find(t => t.GetType
> > > > > > > ().GetGenericArguments()[0] == typeof(T).BaseType);
> > > > > > > Because _mappings contains instances of classes that are
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Fluent NHibernate" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/fluent-nhibernate?hl=en
-~----------~----~----~----~------~----~------~--~---