Maybe we need a instance method on AutoPersistenceModel a la
IncludeEntitiesFromAssembly<T> so we could say:

var model =
AutoPersistenceModel.MapEntitiesFromAssembly<T>.IncludeEntitiesFromAssembly<T>
(... and so on).Where(GetEntityFilter)...
The first call to MapEntitiesFromAssembly<T> would do essentially what
it does now except that it'd save the assembly to an
ICollection<Assembly>. Subsequent calls to
IncludeEntitesFromAssembly<T> would add additional assemblies to that
collection (it'd be prudent to make sure the same assembly isn't added
twice).
Everything from that point on would be business as usual till it came
to CompileMappings in which case we could do something like..

var entitiesToMap = mappingAssemblies.SelectMany(asm =>
asm.GetExportedTypes()).Where(t => shouldInclude(t) && !
Conventions.IsBaseType(t));
entitiesToMap.ForEach(entity => {var mapping = FindMapping(entity); if
(mapping != null) MergeMapping(mapping) else AddMapping(mapping)

(excuse the typos and syntax errors - running on mental compiler
again :-) )

The Where clause above would need to identify entities from all
included assemblies
What do you think?

On Feb 12, 6:01 pm, James Gregory <[email protected]> wrote:
> MapEntitiesFromAssembly<T> creates an instance of an AutoPersistenceModel,
> so you'd need to do something like this to use multiple assemblies:
> var autoMapper1 = AutoPersistenceModel.MapEntitiesFromAssembly<A>();
> var autoMapper2 = AutoPersistenceModel.MapEntitiesFromAssembly<B>();
>
> The problem is, that would only map two separate class hierarchies, and not
> handle any mixing of the two. I don't think it's currently possible to map
> two assemblies as one logical domain. This is something that we should
> support though.On Thu, Feb 12, 2009 at 5:20 PM, Jimit <[email protected]> 
> wrote:
>
> > That unfortunately raises other issues for me - all my base classes
> > including DomainObject are in another assembly (Core.Common) than the
> > one that holds my domain model (Core.Domain). I don't suppose it's
> > possible to call MapEntitiesFromAssembly<T> more than once and filter
> > it with the same predicate in the Where method? I seem to remember
> > MapEntitiesFromAssembly<T> simply saving a reference to the assembly
> > for use later in CompileMappings which would mean that calling it
> > twice would simply reset the reference.
> > What do you think?
>
> > On Feb 12, 8:54 am, James Gregory <[email protected]> wrote:
> > > Yeah, that makes sense. Currently you shouldn't exclude something set
> > with
> > > IsBaseType in your Where clause. That being said, the two should probably
> > > be equivalent really.
>
> > > On Thu, Feb 12, 2009 at 6:10 AM, Jimit <[email protected]> wrote:
>
> > > > I think I may have found the problem. DomainObject was excluded by my
> > > > entity filter in my call to Where on the AutoPersistenceModel (since
> > > > it itself is not an entity, just a common base class for both entities
> > > > and value objects and thus it doesn't have an Id, I figured no need).
> > > > I subsequently did a mapping override using
> > > > ForTypesThatDeriveFrom<DomainObject> which internally populates an
> > > > AutoMap<DomainObject>. In CompileMappings however the conditions that
> > > > would normally exclude DomainObject from the final mapping (i.e the
> > > > checks for shouldInclude and IsBaseType) don't get called for
> > > > DomainObject since it was not in the original list of entities to map.
> > > > It's AutoMap<DomainObject> created by ForTypesThatDeriveFrom is meant
> > > > only to be used by MergeMapping to merge with automaps for classes
> > > > deriving from DomainObject and instead it went to AddMapping. As a
> > > > result it circumvents the checks and ends up getting mapped. Not
> > > > having an Id property, Nhibernate doesn't like that and hence the
> > > > exception. I haven't actually checked the call stacks to verify this
> > > > behaviour - it's all been mental compiler since the realization just
> > > > came to me. :) I'll check it out when I'm at work but it seems to be
> > > > pointing at a loophole in the CompileMapping logic.
>
> > > > On Feb 10, 10:54 pm, Jimit <[email protected]> wrote:
> > > > > This is my test fixture. I configure FNH in the Setup:
>
> > > > >     [TestFixture]
> > > > >     public class PersistenceTests
> > > > >     {
> > > > >         #region Setup/Teardown
>
> > > > >         [SetUp]
> > > > >         public void SetUp()
> > > > >         {
> > > > >             _sessionFactory = Fluently.Configure()
> > > > >                 .Database(SQLiteConfiguration.Standard.InMemory)
> > > > >                 .Mappings(m => m.AutoMappings.Add(Mapper.Mappings))
> > > > >                 .ExposeConfiguration(cfg => new SchemaExport
> > > > > (cfg).Create(true, true))
> > > > >                 .BuildSessionFactory();
> > > > >         }
>
> > > > >         [TearDown]
> > > > >         public void TearDown()
> > > > >         {
> > > > >             _sessionFactory = null;
> > > > >         }
>
> > > > >         #endregion
>
> > > > >         private ISessionFactory _sessionFactory;
>
> > > > >         [Test]
> > > > >         public void Can_Map_Orders_To_Database()
> > > > >         {
> > > > >             new PersistenceSpecification<Order>
> > > > > (_sessionFactory.OpenSession())
> > > > >                 .CheckProperty(o => o.Reference, "Order Ref 1")
> > > > >                   .CheckProperty(o => o.PartsOrdered, 2) /* and so
> > > > > on...*/
> > > > >                 .CheckProperty(o => o.PartsReceived, 1);
> > > > >         }
>
> > > > >     }
>
> > > > > Mapper.Mappings is where the AutoPersistenceModel is defined. Here
> > are
> > > > > the pertinent parts there:
>
> > > > > public static class Mapper
> > > > > {
> > > > >         public static AutoPersistenceModel Mappings
> > > > >         {
> > > > >             get
> > > > >             {
> > > > >                 return _mappings ?? (_mappings = DefineMappings());
> > > > >             }
> > > > >         }
>
> > > > >         private static AutoPersistenceModel DefineMappings()
> > > > >         {
> > > > >             return AutoPersistenceModel
> > > > >                 .MapEntitiesFromAssemblyOf<Order>()
> > > > >                 .Where(EntityFilter)
> > > > >                 .WithConvention(DefineConventions)
> > > > >                 .WithCustomMappingsFrom<CustomMappings>();
> > > > >         }
>
> > > > >         private static void DefineConventions
> > > > > (FluentNHibernate.Conventions conventions)
> > > > >         {
> > > > >             SetDefaultConventions(conventions);
> > > > >             AddCustomConventions(conventions);
> > > > >         }
> > > > >         private static void SetDefaultConventions
> > > > > (FluentNHibernate.Conventions conventions)
> > > > >         {
> > > > >             conventions.GetPrimaryKeyName = property => property.Name
> > > > > + "Id";
> > > > >             conventions.GetPrimaryKeyNameFromType = type => type.Name
> > > > > + "Id";
> > > > >             conventions.GetVersionColumnName = property => "Version";
> > > > >             conventions.IsBaseType = type =>
> > > > >                                      type == typeof (object) ||
> > > > >                                      type == typeof (DomainObject) ||
> > > > >                                      (type.IsGenericType
> > > > >                                       &&
> > type.GetGenericTypeDefinition
> > > > > ().IsIn(new[]
>
> > > > > {
>
> > > > > typeof (EntityBase<,>),
>
> > > > > typeof (EntityBase<>),
>
> > > > > typeof (ProcessedEntity<,>),
>
> > > > > typeof (ProcessedEntity<>),
>
> > > > > typeof (AuditedEntity<,>),
>
> > > > > typeof (AuditedEntity<>),
>
> > > > > typeof (ProcessingEvent<>)
>
> > > >         }));
> > > > >             //conventions.IsComponentType = t => t ==
> > typeof(Address);
> > > > >             conventions.OneToManyConvention = map =>
> > > > > map.Cascade.SaveUpdate();
> > > > >             conventions.DefaultLazyLoad = true;
> > > > >             conventions.GetForeignKeyNameOfParent = parent =>
> > > > > parent.Name + "ID";
> > > > >             conventions.IdConvention = identity => identity
> > > > >                                                        .Access.
>
> > > > > AsReadOnlyPropertyThroughPascalCaseField
>
> > > > > (Prefix.Underscore)
>
> > > >  .GeneratedBy.Native
> > > > > ()
>
> >  .TheColumnNameIs
> > > > > ("Id");
> > > > >             conventions.GetForeignKeyName = property => property.Name
> > > > > + "Id";
> > > > >             conventions.GetManyToManyTableName =
> > > > >                 (parent, child) => parent.Name + "_" + child.Name;
> > > > >             conventions.DefaultCache = cache => cache.AsReadWrite();
> > > > >             conventions.GetParentSideForManyToMany = (type1, type2)
> > =>
> > > > >                                                          {
> > > > >                                                              var
> > types
> > > > > = (new[] {type1, type2})
>
> >  .OrderBy
> > > > > (t => t.Name);
> > > > >                                                              return
> > > > > types.Where(
>
> > > > > t => typeof (IAggregateRoot)
>
> > > >        .IsAssignableFrom
> > > > > (t))
>
> > > > .FirstOrDefault
> > > > > () ??
>
> > > > > types.First();
> > > > >                                                          };
> > > > >         }
>
> > > > >         private static void AddCustomConventions
> > > > > (FluentNHibernate.Conventions conventions)
> > > > >         {
> > > > >             // Add type conventions
> > > > >             conventions.AddTypeConvention(new
> > DescriptionTypeConvention
> > > > > ());
> > > > >             conventions.AddTypeConvention(new NameTypeConvention());
> > > > >             conventions.AddTypeConvention(new ReferenceTypeConvention
> > > > > ());
>
> > > > >             // Add property conventions
> > > > >             conventions.AddPropertyConvention(new
> > > > > ForeignKeyMapsToEnum<Order>(o => o.Status));
> > > > >             conventions.AddPropertyConvention(new AuditingConvention
> > > > > ());
> > > > >         }
>
> > > > >         public static AutoPersistenceModel
> > > > > WithCustomMappingsFrom<TCustomMapper>(this AutoPersistenceModel
> > model)
> > > > >         {
> > > > >             (from method in typeof (TCustomMapper).GetMethods()
> > > > >              where method.DeclaringType == typeof (TCustomMapper)
> > > > >                    && method.ReturnType == typeof (void)
> > > > >                    && method.GetParameters().Count() == 1 &&
> > > > >                    method.GetParameters()[0].ParameterType.
> > > > >                        GetGenericTypeDefinition() ==
> > > > >                    typeof (AutoMap<>)
> > > > >              select method).ForEach(method =>
> > > > >                                         {
> > > > >                                             var autoMapType =
> > > > > method.GetParameters()[0].ParameterType;
> > > > >                                             var entityType =
> > > > > autoMapType.GetGenericArguments()[0];
> > > > >                                             var actionType = typeof
> > > > > (Action<>).MakeGenericType(new[] {autoMapType});
> > > > >                                             var mappingAction = new[]
> > > > > {Delegate.CreateDelegate(actionType, method)};
>
> > > > > InvocationHelper.InvokeGenericMethodWithDynamicTypeArguments(
> > > > >                                                 model,
> > > > >                                                 map =>
> > > > > map.ForTypesThatDeriveFrom<Object>(null),
> > > > >                                                 mappingAction,
> > > > >                                                 entityType);
> > > > >                                         });
> > > > >             return model;
> > > > >         }
>
> > > > > }
>
> > > > > The relevent action in CustomMappings is:
>
> > > > >     public class CustomMappings
> > > > >     {
> > > > >         public static void ProcessMapping(AutoMap<DomainObject> map)
> > > > >         {
> > > > >             map.Version(o => o.Version)
> > > > >                 .Access.AsReadOnlyPropertyThroughPascalCaseField
> > > > > (Prefix.Underscore);
> > > > >             map.IgnoreProperty(o => o.IsValid);
> > > > >             map.IgnoreProperty(o => o.Error);
> > > > >         }
>
> > > > >        // other mapping overrides
> > > > >     }
>
> > > > > On Feb 10, 12:07 pm, James Gregory <[email protected]> wrote:
>
> > > > > > Can we see how you're setting your conventions and where you're
> > > > plumbing FNH
> > > > > > into NHibernate?
>
> > > > > > On Tue, Feb 10, 2009 at 12:01 PM, Jimit <[email protected]>
> > wrote:
>
> > > > > > > I get the following error when attempting to test my mappings:
>
> > > > > > > <?xml version="1.0" encoding="utf-8"?>
> > > > > > > <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-
> > > > > > > lazy="true" assembly="Core.Common"
> > namespace="Core.Common.Entities">
> > > > > > >  <class name="DomainObject" table="`DomainObject`"
> > > > > > > xmlns="urn:nhibernate-mapping-2.2">
> > > > > > >    <cache usage="read-write" />
> > > > > > >    <version
>
> > > ...
>
> > > read more »- Hide quoted text -
>
> > > - Show quoted text -
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to