Showing posts with label NHibernate. Show all posts
Showing posts with label NHibernate. Show all posts

Wednesday, February 15, 2012

NHibermate 3.2: mapping by code complete guide

Adam Bar wrote a list of posts on his blog about the NHibernate mapping by code, also known as loquacious mapping.
So far, this is the only complete guide on the web about the new xml-less mapping.
A great job has been done with many comparisons between xml and FluentNHibernate mapping.

The summary is here:
http://notherdev.blogspot.com/2012/02/nhibernates-mapping-by-code-summary.html

Have a nice read :)

Monday, January 23, 2012

NHibernate proxy of incorrect type exception: "PropertyAccessException Invalid Cast (check your mapping for property type mismatches)"

Are you facing this exception?

NHibernate.PropertyAccessException : Invalid Cast (check your mapping for property type mismatches); setter of MyEntity ----> System.InvalidCastException : Unable to cast object of type 'MyOtherEntityProxy' to type 'AnotherEntity'.

Looking on google, I saw that other programmers have this type of problem.

This article can help you if you are using Ninject and uNhAddIns.NinjectAdapters for entity injection in NHibernate.

If you are using the "NinjectAdapter" assembly, you need to bind the IProxyFactory interface to a class, for example to the default provided with NHibernate, DefaultProxyFactory, if is good for you.
My problem was the definition of this bind in a Ninject kernel module, copied from somewhere on the net or from a book, I can't remember.
   Bind<NHibernate.Proxy.IProxyFactory>()
      .To<NHibernate.Proxy.DefaultProxyFactory>()
      .InSingletonScope(); // <= here the problem


Declaring this bind in singleton scope is not good because the instance will be shared between NHibernate entities metadata classes: so you will get always the first ProxyFactory instance created and you will receive an error like the one above at runtime when you need a proxy classes of a type different from the first one created.

Was really a pain and take a lot of time to find out the problem as you can image, and the solution is to declare the bind InTransientScope(), of course.

   Bind<NHibernate.Proxy.IProxyFactory>()
      .To<NHibernate.Proxy.DefaultProxyFactory>()
      .InTransientScope(); // <= problem fixed

Here the documentation about the object scopes in Ninject.

Doing a similar mistake, you could have the same problem with another dependency injection library like Sprint.Net or CastleWindsor, of course.

Hope it helps :)

Wednesday, January 4, 2012

NHibernate mapping by code a sequence generator

How to map an identifier when you want to use a sequence generator, like the one used by PosrgreSQL ?
Here is an example in the loquacious way using the ClassMapping<T> base class, and, of course, the MapperModel:

   public sealed class MyEntityMap : ClassMapping<MyEntity>
   {
      public MyEntityMap ()
      {
         Table("my_table");
         Id(x => x.Id,
            a =>
            {
               a.Column("my_id");
               a.Generator(Generators.Sequence, g => g.Params(new
               {
                  sequence = "my_sequence_generator"
               }));
            });
      }
   }

Happy mapping ^^

Monday, December 5, 2011

NullReferenceException on CompileMappingForAllExplicitlyAddedEntities ModelMapper for NHibernate 3.2

If you're using NHibernate 3.2, and when call the CompileMappingForAllExplicitlyAddedEntities() method of your ModelMapper object, you have to check none of your added classes are defined without a namespace.
This could happen if you are added all types defined in your assemblies (calling for example mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes() ), and at least one of your classes is compiled in the empty namespace ...
To solve this error, you have to define these classes in a namespace (it is always a good practice).

The error is caused by the NHibernate source code, because doesn't take care about empty namespaces.

The thread about that problem on nhuser google group.

Happy debugging ^^

Saturday, November 26, 2011

NHibernate MappingByCode ManyToMany

I was not able to find a "loquacious" conformist example about a many-to-many relation mapping, so after play a bit with it, I finally deal with it.
Here an example:

 Bag(x => x.ManyToManyCollection
   , map =>
     {
        map.Table("many_to_many_table_name");
        map.Lazy(CollectionLazy.Lazy);
        map.Key(k => k.Column("child_key_column"));
     }
   , action => action.ManyToMany(m => m.Column("parent_key_column")));

Happy mapping! ^^

Wednesday, November 16, 2011

NHibernate.MappingException: Could not determine type for: MyClass, for columns: NHibernate.Mapping.Column(id)

If you are using conformist mapping-by-code introduced by NHibernate in the 3.2, and are facing this exception maybe you have another problem.
If you define a Bag map like this
Bag(x => x.CollectionProp
     , map =>
     {
        map.Key(km => km.Column("col_id"));
        map.Cascade(Cascade.All | Cascade.DeleteOrphans);
     });
for a one-to-many association, you will retrieve this (misleading) exception. To solve it you have to specific the action in a way like this:
Bag(x => x.CollectionProp
     , map =>
     {
        map.Key(km => km.Column("col_id"));
        map.Cascade(Cascade.All | Cascade.DeleteOrphans);
     }
     , action => action.OneToMany()
    );
A post about it on stack overflow.

NHibernate loquacious mapping config

Edit 2012/01/21: added some overloads to retrieve assemblies metadata loaded. This can be useful in many way, my one is the ability to serialize NHibernate configuration, like explained here.





I just publish a very small project for who uses NHibernate: it allows to use the web.config or app.config of your application to set up what assemblies load for the mapping in the "conformist" way.
For who doesn't know it, NHibernate is probably the best ORM for .NET existing on the way: and it's open source.
Loquacius mapping is the new "mapping by code" way introduced in 3.2 that basically comes from Fabio Maulo’s ConfORM.
Here's the link of the project: https://github.com/michelelepri/NHibernate.LoquaciousMappingConfig

How to set up all:
  1. download and compile de project;
  2. add to your .config file a section to the configSection node like this:
    <section
       name="loquaciousNHibernateMapping"
       type="NHibernate.LoquaciousMappingConfig.Config.LoquaciousNHibernateMappingSection, NHibernate.LoquaciousMappingConfig"/>
    
  3. add the configuration containing the list of your assemblies:
    <loquaciousNHibernateMapping>
          <assemblies>
             <add assembly="YourAssebly"/>
          </assemblies>
       </loquaciousNHibernateMapping>
    
  4. call the extended method to read the configuration and load the assemblies:
    var cfg = new Configuration().Configure();
    
    // your other coded config stuff
    
    var mapper = new ModelMapper();
    mapper.AddFromConfig(); // here the lib extended method
    var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
    cfg.AddDeserializedMapping(mapping, "yourDocumentName");
    var sessionFactory = cfg.BuildSessionFactory(); 
All done !

I found it very useful in my (quite big) project to use both FluentNHibernate and the mapping-by-code cause I would like to migrate all the maps to the loquacious one.
Simply add these lines of code after the cfg.AddDeserializadMapping(..)  and replace the SessionFactory build:

// reuse the same cfg object with the mapping by code just added
var sessionFactory = Fluently.Configure(cfg)
    .Mappings(x => x.FluentMappings.AddFromAssemblyOf<YourClass>() /* or the method you like */)
    .BuildSessionFactory();

So you will have both fluent and loquacious mapping in your projects.

Happy coding! :)