Fluent NHibernate + AutoMap + Observable

2.1k views Asked by At

I'm new to Fluent NHibernate but was drawn by the Automapping and otherwise great featureset of the platform. I'm having trouble with getting an ObservableCollection setup, I've scoured the web and tried many different things and all of them have led me back to the same error:

FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

 ---> FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

 ---> System.ArgumentException: Cannot create an instance of FluentNHibernate.Automapping.AutoMapping`1[uNhAddIns.WPF.Collections.Types.ObservableListType`1[T]] because Type.ContainsGenericParameters is true.
   at System.RuntimeType.CreateInstanceCheckThis()
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at FluentNHibernate.Automapping.AutoMapper.ApplyOverrides(Type classType, IList`1 mappedMembers, ClassMappingBase mapping) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoMapper.cs:line 28
   at FluentNHibernate.Automapping.AutoMapper.MergeMap(Type classType, ClassMappingBase mapping, IList`1 mappedMembers) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoMapper.cs:line 41
   at FluentNHibernate.Automapping.AutoMapper.Map(Type classType, List`1 types) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoMapper.cs:line 176
   at FluentNHibernate.Automapping.AutoPersistenceModel.AddMapping(Type type) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoPersistenceModel.cs:line 185
   at FluentNHibernate.Automapping.AutoPersistenceModel.CompileMappings() in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoPersistenceModel.cs:line 149
   at FluentNHibernate.Automapping.AutoPersistenceModel.Configure(Configuration configuration) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Automapping\AutoPersistenceModel.cs:line 175
   at FluentNHibernate.Cfg.AutoMappingsContainer.Apply(Configuration cfg) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\AutoMappingsContainer.cs:line 84
   at FluentNHibernate.Cfg.MappingConfiguration.Apply(Configuration cfg) in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\MappingConfiguration.cs:line 66
   at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration() in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 128
   --- End of inner exception stack trace ---
   at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration() in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 139
   at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 108
   --- End of inner exception stack trace ---
   at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH-v1.x-nh3\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 113
   at ToDoIt2.Model.Document.<Initialize>b__0() in C:\data\svn\WPF\vs2010\ToDoIt2\Application\Model\Document.cs:line 54
   at ToDoIt2.App.DisplayException(NoArgsDelegate z) in C:\data\svn\WPF\vs2010\ToDoIt2\Application\App.xaml.cs:line 66

This being the applicable line:

---> System.ArgumentException: Cannot create an instance of 
FluentNHibernate.Automapping.AutoMapping`1[uNhAddIns.WPF.Collections.Types.ObservableListType`1[T]]
because Type.ContainsGenericParameters is true.

Here is the class I am trying to map:

public class Item {
    public virtual int ItemID { get; set; }
    public virtual string Title { get; set; }
    public virtual ObservableListType<string> Children { get; set; }
}

Using uNhAddIns.WPF.Collections.Types.ObservableListType from uNhAddIns.

Here is my AutoMapping:

this.FluentConfig = Fluently.Configure()
                    .Mappings(m => m.AutoMappings
                        .Add(AutoMap
                            .Assemblies(new ToDoIt2.DB.AutoMapping(), 
                                Assembly.GetExecutingAssembly(),
                                Assembly.GetAssembly(typeof(ObservableListType<>))
                            )
                            .IgnoreBase<pklib.DataObject>()
                            .Conventions.Add<myPrimaryKeyConvention>()
                            .Conventions.Add<myForeignKeyConvention>()
                        ));  

Answer From @Diego

Domain Entity needed to change to:

public class Item {
    public virtual int ItemID { get; set; }
    public virtual string Title { get; set; }
    public virtual ICollection<string> Children { get; set; }
}

Fluent Configuration Changed To:

this.FluentConfig = Fluently.Configure()
        .ExposeConfiguration(cfg => cfg.SetProperty(NHibernate.Cfg.Environment.CollectionTypeFactoryClass,
             typeof(WpfCollectionTypeFactory).AssemblyQualifiedName))
        .Mappings(m => m.AutoMappings
            .Add(AutoMap
                .Assemblies(new ToDoIt2.DB.AutoMapping(), 
                    Assembly.GetExecutingAssembly(),
                    Assembly.GetAssembly(typeof(ObservableListType<>))
                )
                .IgnoreBase<pklib.DataObject>()
                .Conventions.Add<myPrimaryKeyConvention>()
                .Conventions.Add<myForeignKeyConvention>()
            ));
1

There are 1 answers

1
Diego Mijelshon On BEST ANSWER

You are not supposed to directly use ObservableListType in your classes and mappings (use ICollection<T>, IList<T>, etc)

Instead, you need to use WpfCollectionTypeFactory as the collection type factory.

In XML configuration, this is done by setting collectiontype.factory_class="uNhAddIns.WPF.Collections.WpfCollectionTypeFactory, uNhAddIns.WPF".

I don't know if Fluent has any shortcuts, but you can use the following:

.ExposeConfiguration(cfg => SetProperty(Environment.CollectionTypeFactoryClass,
                         typeof(WpfCollectionTypeFactory).AssemblyQualifiedName))