Try fast search NHibernate

18 April 2011

me on Fluent NHibernate

Well… from where I should start ?…?? Perhaps from “Mapping Source: How map a class without use XML” mmm… no, better no because it is too old and was classified as “too complicated”. Perhaps from “Map NHibernate using your API” mmm… no, better no because it is one year old and was classified as “too silly” as you can read in the comments of this post and in this other. What about this “NHibernate is notorious for having an obtuse and unfriendly API” … perhaps… perhaps… and what you think about this ?
frankly_jamesgregory
Would you help me to translate the above phrase ?

Or perhaps you want know something more ?
frankly_fm1
frankly_fm2
frankly_fm3
I can continue but frankly I have my ba…ehm.. sorry… I mean… I’m something tired of this situation.

Since the begin of FluentNHibernate the attitude was the same: say that NHibernate is a shit and you will be happy. Since the begin of FluentNHibernate we have asked a patch or something and the result was zero lines of code but each time I, or we (the team), do something, somebody come with the same aseptic critics without a single line of C# code. Which is the point ? What mean “Fluent NHibernate is smaller and more flexible than NHibernate” ? More than 600 *.cs files “only” to create a mapping is smaller than what ? an entirely ORM framework ? What is FNH without NHibernate ? bah?!??!?

I done ConfORM yes!! why ? I have asked to the team and the team said “if it will be not ready for 3.0 then please do it out from core” and in that time I was needing something to do a specific big work. Few days ago I have asked again and the team gave me its “OK!!”.

There are people arguing that ConfORM is the same of FluentNHibernate but with an ugly API. WOW!! THANKS!! you are saying that I done the same work, alone and in my free time within less than 3 months, with more flexibility and around 250 *.cs files instead more than 600. But are you really sure that I’m doing the same ? I think that ConfORM is more powerful than FNH but this is not the point. Each time I have published a post about ConfORM some FNH’s fanatics had the pleasure to ask me the same example but using FNH… ehi MAN!! do you haven’t something else to do ? FNH team ask me (not to the team but to me directly) that I have to implement a public API to let FNH avoid XMLs, FNH users ask to me to publish my examples about ConfORM but using FNH…when I implement another public API, to create mapping, again there is something else to do in another way…  are you crazy or what ?

The discussion about the API, of explicit mapping, used in NHibernate is again another point where people like to say something. That API was proposed to the team and the team have discussed it (and this is not the first time I’m saying the same as you can read here and here and here if you follow all links in those posts). We “imitate” the XML simplifying it where possible. If a user know XML then he can understand and follow the new API. All existing documentation is reusable. Which was the proposal of some FNH’s fanatic ? “you have to use the API of FNH instead that ugly API”… What ? Which will be the end of FluentNHibernate project if NH includes that API ?

All decisions was and are discussed by the team because NH not only has a big community but even is not “one man show”; NHibernate is a team!! We are following MVCs (Most Valuable Contributors) in our JIRA and around the NET and each year we invite some MVCs to become committers. Because I really care about NHibernate, so much that I have more than 1400 commits only in the core, I’m pushing people to implement more and more options to map it. I’m asking myself the reason because some FluentNHibernate fanatics are so blind to don’t see the point.

After these few words its time to show you the code. This time I’ll not use words as “Map NHibernate using your API” or “Map NHibernate using your DSL” (a vague reference to the recipient of the message) but… well… you will see.

Mapping class-by-class

The target is, using the high-level API of NHibernate 3.2, implement what is needed to use this other final API:
public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        Id(x => x.Id);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        References(x => x.Store);
    }
}

public class LocationMap : ComponentMap<Location>
{
    public LocationMap()
    {
        Map(x => x.Aisle);
        Map(x => x.Shelf);
    }
}

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Map(x => x.Price);
        HasManyToMany(x => x.StoresStockedIn)
            .Cascade.All()
            .Inverse()
            .Table("StoreProduct");

        Component(x => x.Location);
    }
}

public class StoreMap : ClassMap<Store>
{
    public StoreMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        HasManyToMany(x => x.Products)
            .Cascade.All()
            .Table("StoreProduct");
        HasMany(x => x.Staff)
            .Cascade.All()
            .Inverse();
    }
}
If you haven’t recognized it, the code is exactly the FluentNHibernate’s example available in FNH repository, the domain is obviously the same and the Program to run is pretty the same (I have to change the configuration to build the SessionFactory using the new implementations below).

All classes/interfaces needed to reproduce the Fluent-NHibernate’s API using the NHibernate 3.2 high-level API are:
public class ClassMap<T> : IMappingProvider where T : class
{
    private readonly ClassMapping<T> mapper = new ClassMapping<T>();

    public IdentityPart<T, TProperty> Id<TProperty>(Expression<Func<T, TProperty>> idProperty)
    {
        return new IdentityPart<T, TProperty>(mapper, idProperty);
    }

    public PropertyBuilder<T, TProperty> Map<TProperty>(Expression<Func<T, TProperty>> property)
    {
        return new PropertyBuilder<T, TProperty>(mapper, property);
    }

    public ManyToOneBuilder<T, TOther> References<TOther>(Expression<Func<T, TOther>> property) where TOther : class
    {
        return new ManyToOneBuilder<T, TOther>(mapper, property);
    }

    public IOneToManyPart HasMany<TChild>(Expression<Func<T, IEnumerable<TChild>>> property)
    {
        // TODO: In FNH you have to find the way to know the type of the collection (Bag,Set,List etc.);
        return new OneToManyPart<T, TChild, IBagPropertiesMapper<T, TChild>>(property, mapper.Bag);
    }

    public IManyToManyPart HasManyToMany<TChild>(Expression<Func<T, IEnumerable<TChild>>> property)
    {
        // TODO: In FNH you have to find the way to know the type of the collection (Bag,Set,List etc.);
        return new ManyToManyPart<T, TChild, IBagPropertiesMapper<T, TChild>>(property, mapper.Bag);
    }

    public void Component<TComponent>(Expression<Func<T, TComponent>> property) where TComponent: class
    {
        // TODO: In FNH you have to do the others stuff you need to return the "fluent" interface
        mapper.Component(property);
    }

    IConformistHoldersProvider IMappingProvider.GetNHibernateMapping()
    {
        return mapper;
    }
}

public class ComponentMap<T> : IMappingProvider where T : class
{
    private readonly ComponentMapping<T> mapper = new ComponentMapping<T>();

    public PropertyBuilder<T, TProperty> Map<TProperty>(Expression<Func<T, TProperty>> property)
    {
        return new PropertyBuilder<T, TProperty>(mapper, property);
    }

    IConformistHoldersProvider IMappingProvider.GetNHibernateMapping()
    {
        return mapper;
    }
}


public interface IMappingProvider
{
    IConformistHoldersProvider GetNHibernateMapping();
}

public class IdentityPart<T, TProperty> where T : class
{
    private readonly ClassMapping<T> mapper;
    private readonly Expression<Func<T, TProperty>> idProperty;

    public IdentityPart(ClassMapping<T> classMapping, Expression<Func<T, TProperty>> idProperty)
    {
        this.mapper = classMapping;
        this.idProperty = idProperty;
        mapper.Id(idProperty, x => { });
    }

    public IdentityPart<T, TProperty> Column(string columnName)
    {
        mapper.Id(idProperty, x => x.Column(columnName));
        return this;
    }
}

public class PropertyBuilder<T, TProperty> where T : class
{
    private readonly IPropertyContainerMapper<T> mapper;
    private readonly Expression<Func<T, TProperty>> property;

    public PropertyBuilder(IPropertyContainerMapper<T> classMapping, Expression<Func<T, TProperty>> property)
    {
        this.mapper = classMapping;
        this.property = property;
        mapper.Property(property, x => { });
    }

    public PropertyBuilder<T, TProperty> Column(string columnName)
    {
        mapper.Property(property, x => x.Column(columnName));
        return this;
    }
}

public class ManyToOneBuilder<T, TOther>
    where T : class
    where TOther : class
{
    private readonly ClassMapping<T> mapper;
    private readonly Expression<Func<T, TOther>> property;

    public ManyToOneBuilder(ClassMapping<T> classMapping, Expression<Func<T, TOther>> property)
    {
        this.mapper = classMapping;
        this.property = property;
        mapper.ManyToOne(property, x => { });
    }

    public ManyToOneBuilder<T, TOther> Column(string columnName)
    {
        mapper.ManyToOne(property, x => x.Column(columnName));
        return this;
    }
}

public interface ICollectionAttributesApplier<T, TChild> where T : class
{
    void ApplyAttributes(Action<ICollectionPropertiesMapper<T, TChild>> apply);
}

public interface IOneToManyPart
{
    ICollectionCascadeExpression<IOneToManyPart> Cascade { get; }
    IOneToManyPart Inverse();
}

public class OneToManyPart<T, TChild, TCollectionCustomizer> : ICollectionAttributesApplier<T, TChild>, IOneToManyPart
    where T : class
    where TCollectionCustomizer : ICollectionPropertiesMapper<T, TChild>
{
    private readonly Expression<Func<T, IEnumerable<TChild>>> property;
    private readonly Action<Expression<Func<T, IEnumerable<TChild>>>, Action<TCollectionCustomizer>, Action<ICollectionElementRelation<TChild>>> customizer;

    public OneToManyPart(Expression<Func<T, IEnumerable<TChild>>> property,
                         Action<Expression<Func<T, IEnumerable<TChild>>>, Action<TCollectionCustomizer>, Action<ICollectionElementRelation<TChild>>> customizer)
    {
        this.property = property;
        this.customizer = customizer;
        ApplyRelation(x => x.OneToMany());
    }

    public ICollectionCascadeExpression<IOneToManyPart> Cascade
    {
        get { return new CollectionCascadeExpression<IOneToManyPart, T, TChild, OneToManyPart<T, TChild, TCollectionCustomizer>>(this, this); }
    }

    public IOneToManyPart Inverse()
    {
        ApplyAttributes(x => x.Inverse(true));
        return this;
    }

    public void ApplyAttributes(Action<ICollectionPropertiesMapper<T, TChild>> apply)
    {
        customizer(property, att => apply(att), rel => { });
    }

    private void ApplyRelation(Action<ICollectionElementRelation<TChild>> apply)
    {
        customizer(property, x => { }, apply);
    }
}

public interface IManyToManyPart
{
    ICollectionCascadeExpression<IManyToManyPart> Cascade { get; }
    IManyToManyPart Table(string tableName);
    IManyToManyPart Inverse();
}

public class ManyToManyPart<T, TChild, TCollectionCustomizer> : ICollectionAttributesApplier<T, TChild>, IManyToManyPart
    where T : class
    where TCollectionCustomizer : ICollectionPropertiesMapper<T, TChild>
{
    private readonly Expression<Func<T, IEnumerable<TChild>>> property;
    private readonly Action<Expression<Func<T, IEnumerable<TChild>>>, Action<TCollectionCustomizer>, Action<ICollectionElementRelation<TChild>>> customizer;

    public ManyToManyPart(Expression<Func<T, IEnumerable<TChild>>> property,
                          Action<Expression<Func<T, IEnumerable<TChild>>>, Action<TCollectionCustomizer>, Action<ICollectionElementRelation<TChild>>> customizer)
    {
        this.property = property;
        this.customizer = customizer;
        ApplyRelation(x => x.OneToMany());
    }

    public ICollectionCascadeExpression<IManyToManyPart> Cascade
    {
        get { return new CollectionCascadeExpression<IManyToManyPart, T, TChild, ManyToManyPart<T, TChild, TCollectionCustomizer>>(this, this); }
    }

    public IManyToManyPart Inverse()
    {
        ApplyAttributes(x => x.Inverse(true));
        return this;
    }

    public IManyToManyPart Table(string tableName)
    {
        ApplyAttributes(x => x.Table(tableName));
        return this;
    }

    public void ApplyAttributes(Action<ICollectionPropertiesMapper<T, TChild>> apply)
    {
        customizer(property, att => apply(att), rel => { });
    }

    private void ApplyRelation(Action<ICollectionElementRelation<TChild>> apply)
    {
        customizer(property, x => { }, apply);
    }
}

public interface ICollectionCascadeExpression<TParent>
{
    TParent All();
    TParent DeleteOrphan();
    TParent AllDeleteOrphan();
}

public class CollectionCascadeExpression<TParent, TContainer, TChild, TApplier> : ICollectionCascadeExpression<TParent>
    where TParent : class
    where TContainer : class
    where TApplier : ICollectionAttributesApplier<TContainer, TChild>
{
    private readonly TParent parent;
    private readonly TApplier applier;

    public CollectionCascadeExpression(TParent parent, TApplier applier)
    {
        this.parent = parent;
        this.applier = applier;
    }

    public TParent All()
    {
        applier.ApplyAttributes(x => x.Cascade(Cascade.All));
        return parent;
    }

    public TParent DeleteOrphan()
    {
        applier.ApplyAttributes(x => x.Cascade(Cascade.DeleteOrphans));
        return parent;
    }

    public TParent AllDeleteOrphan()
    {
        applier.ApplyAttributes(x => x.Cascade(Cascade.All.Include(Cascade.DeleteOrphans)));
        return parent;
    }
}

The code used for the method to build the SessionFactory is:
private static ISessionFactory CreateSessionFactory()
{
    var configure = new Configuration();
    configure.DataBaseIntegration(x =>
    {
        x.Dialect<MsSql2008Dialect>();
        x.ConnectionString = (new SqlConnectionStringBuilder
        {
            DataSource = @"localhost\SQLEXPRESS",
            InitialCatalog = "reFNH",
            IntegratedSecurity = true
        }).ToString();
        x.SchemaAction = SchemaAutoAction.Recreate;
    });
    return configure.AddMappingsFromAssemblyOf<Program>().BuildSessionFactory();
}

The extension method to add all mappings using the new implementations is:
public static Configuration AddMappingsFromAssemblyOf<T>(this Configuration conf)
{
    var mapper = new ModelMapper();
    mapper.BeforeMapClass += (mi, t, cam) => cam.Id(x => x.Generator(Generators.Native));

    foreach (Type type in typeof(T).Assembly.GetExportedTypes().Where(x => typeof(IMappingProvider).IsAssignableFrom(x) && !x.IsGenericTypeDefinition && !x.IsInterface))
    {
        IMappingProvider mappingInstance;
        try
        {
            mappingInstance = (IMappingProvider)Activator.CreateInstance(type);
        }
        catch (Exception e)
        {
            throw new MappingException("Unable to instantiate mapping class (see InnerException): " + type, e);
        }
        mapper.AddMapping(mappingInstance.GetNHibernateMapping());
    }

    conf.AddDeserializedMapping(mapper.CompileMappingForAllExplicitAddedEntities(), "Domain");
    return conf;
}

Conclusion

Now not only you have the API you was asking for 3 years (implemented as we need) but you have even the starting point to use it in Fluent-NHibernate and put the turbo to your framework. If you want/need you can use a more low-level API; the name space where look is NHibernate.Mapping.ByCode.Impl .If you need something else, please let me know.

P.S. About “”auto”” mapping I’ll be back soon.

13 April 2011

NHibernate 3.2: mapping by code conventions

GallettiAlloSpiedo

After see some characteristic of one of the new NHibernate 3.2 feature it’s the time to see if the mapping by-code gives support to a convention based mapping. In NHibernate there isn’t a real difference between declarative-mapping and convention-based-mapping because every thing live together since the first commit.

What you will see in this post is defined, by some people, as “auto-mapping”. We don’t have such pretention, and we don’t need to sell something so we are far away to call it auto-mapping but you are free to call it as you want.

For the coming soon version we took the decision to avoid to override the tables/columns naming-convention provided by NHibernate XML mapping; the same for cascade.

The domain model

The model was provided by a NHibernate user: Luka (cluka23)

NHConventions

Well… not so complicated but even not so simple Winking smile

The mapping

Luka have sent me the conformist-mapping so I can understand which is his target. Only to have a little bit of fun I have added two fields for two collections (see class Application). The whole mapping with conventions and registration in NHibernate’s configuration is:

  1.     var mapper = new ConventionModelMapper();
  2.  
  3.     var baseEntityType = typeof(Entity);
  4.     mapper.IsEntity((t, declared) => baseEntityType.IsAssignableFrom(t) && baseEntityType != t && !t.IsInterface);
  5.     mapper.IsRootEntity((t, declared) => baseEntityType.Equals(t.BaseType));
  6.  
  7.     mapper.BeforeMapManyToOne += (insp, prop, map) => map.Column(prop.LocalMember.GetPropertyOrFieldType().Name + "Id");
  8.     mapper.BeforeMapManyToOne += (insp, prop, map) => map.Cascade(Cascade.Persist);
  9.     mapper.BeforeMapBag += (insp, prop, map) => map.Key(km => km.Column(prop.GetContainerEntity(insp).Name + "Id"));
  10.     mapper.BeforeMapBag += (insp, prop, map) => map.Cascade(Cascade.All);
  11.  
  12.     mapper.Class<Entity>(map =>
  13.     {
  14.         map.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
  15.         map.Version(x => x.Version, m => m.Generated(VersionGeneration.Always));
  16.     });
  17.  
  18.     mapper.Class<Person>(map => map.Property(x => x.Name, pm => pm.Column("PersonName")));
  19.     mapper.Class<Tenant>(map => map.Bag(x => x.AppTenants, cm => cm.Inverse(true), r => { }));
  20.     mapper.Class<Customer>(map => map.Bag(x => x.Tenants, cm => cm.Inverse(true), r => { }));
  21.     mapper.Class<Application>(map =>
  22.     {
  23.         map.Bag(x => x.AppFeatures, cm => cm.Inverse(true), r => { });
  24.         map.Bag(x => x.AppTenants, cm => cm.Inverse(true), r => { });
  25.         map.Bag(x => x.Users, cm => cm.Inverse(true), r => { });
  26.     });
  27.  
  28.     var mapping = mapper.CompileMappingFor(baseEntityType.Assembly.GetExportedTypes().Where(t => t.Namespace.EndsWith("Model")));
  29.  
  30.     nhConf.AddDeserializedMapping(mapping,"LukaModel");

Line 4: predicate to recognize entities.

Line 5: predicate to recognize root entities.

From line 7 to 10: some conventions.

From line 12 to 16: some specific mapping of some properties strongly mapped using the base Entity class

From line 18 to 26: some specific mapping of some properties for others entities

Line 28: the creation of the mapping for the whole domain

Line 30: registration of the mapping in the NHibernate configuration.

As you can see there isn’t something special to override conventions, it is all the same you can use with explicit mapping.

If you can’t resist to have a specific class to override a convention you can use something like this:

public class ApplicationMapOverride: ClassMapping<Application>
{
    public ApplicationMapOverride()
    {
        Bag(x => x.AppFeatures, cm => cm.Inverse(true), r => { });
        Bag(x => x.AppTenants, cm => cm.Inverse(true), r => { });
        Bag(x => x.Users, cm => cm.Inverse(true), r => { });
    }
}

“Ehy!! Fabio, you are wrong!! that class is for conformist-mapping.” No, I’m not wrong. You can use the same identical classes to override your conventions, the same classes you can use for declarative mapping. Not only this but can even mix altogether:

mapper.Class<Person>(map => map.Property(x => x.Name, pm => pm.Column("PersonName")));
mapper.Class<Tenant>(map => map.Bag(x => x.AppTenants, cm => cm.Inverse(true), r => { }));
mapper.Class<Customer>(map => map.Bag(x => x.Tenants, cm => cm.Inverse(true), r => { }));
mapper.AddMapping<ApplicationMapOverride>();

“and the two fields ?” those two fields was mapped, don’t worry. If you want see a chuck of the XML:

<bag name="AppFeatures" access="nosetter.camelcase" inverse="true" cascade="all">
  <key column="ApplicationId" />
  <one-to-many class="AppFeature" />
</bag>
<bag name="AppTenants" access="nosetter.camelcase-underscore" inverse="true" cascade="all">
  <key column="ApplicationId" />
  <one-to-many class="AppTenant" />
</bag>

 NHibernate 3.2 too sexy by far!!!

08 April 2011

NHibernate 3.2: (part 2) mapping by code

GallettoAllaDiavola

In the first post about the new mapping-by-code feature you saw only the very first presentation.

I’ll will try to write more posts about this new feature and all its secrets even if you can learn more using ConfORM.

As in ConfORM even the NHibernate’s mapping-by-code is smarter than XML mapping and may help you in many cases. Well… it is not so smart as ConfORM but smart enough to prevent some common errors.

It’s beginner proof

Let me show you a simple case:

private class Person
{
    public int Id { get; set; }
    public ICollection<Address> Addresses { get; set; }
}

private class Address
{
    public Person Owner { get; set; }
    public string Street { get; set; }
    public Number Number { get; set; }
}

private class Number
{
    public Address OwnerAddress { get; set; }
    public int Block { get; set; }
}

An entity with a collection of components which has a nested component. The beginner may intent this mapping:

mapper.Class<Person>(cm =>
{
    cm.Id(x => x.Id);
    cm.Bag(x => x.Addresses, cp => { }, cr => cr.Component(ce =>
    {
        ce.ManyToOne(x => x.Owner);
        ce.Property(x => x.Street);
        ce.Component(x => x.Number, y =>
        {
            y.Component(x => x.OwnerAddress, map => { });
            y.Property(x => x.Block);
        });
    }));
});

hmmmm… a cyclic mapping of the nested component on OwnerAdress property ? Not for sure!! NHibernate knows how create the correct mapping Winking smile.

It’s even conformist

In these years I saw people writing mappings by-code but class-by-class as in XML… a very conformist attitude. Well… if you feel conformist don’t worry NHibernate 3.2 can be conformist too.

public class MyClass
{
    public virtual int Id { get; set; }
    public virtual string Something { get; set; }
}

public class MyClassMap: ClassMapping<MyClass>
{
    public MyClassMap()
    {
        Id(x => x.Id, map =>
        {
            map.Column("MyClassId");
            map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
        });
        Property(x => x.Something, map => map.Length(150));
    }
}

Then you can add it to the ModelMapper in this way:

mapper.AddMappings(typeof(AnyMappingClass).Assembly.GetTypes());

NHibernate 3.2 too sexy by far!!!

01 April 2011

NHibernate 3.2 mapping by code

NHibernate 3.2 will come with its own embedded mapping by code.GalloAlHornoConPapas

If you want know it is not based in fluent-interface, instead it is based on “loquacious”. That said you should understand that it has nothing related with Fluent-NHibernate.

The main idea under the NHibernate’s “sexy mapping” came from my dear ConfORM. In the past year the no conformist red man was running a lot and now I’m ready to transfer most of ConfORM’s intelligence directly inside NHibernate. To continue reading this post you have to run this song.

It’s simple (I’m too sexy)

Simple model

public class MyClass
{
    public int Id { get; set; }
    public string Something { get; set; }
}

Simple mapping

var mapper = new ModelMapper();
mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map =>
    {
        map.Column("MyClassId");
        map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
    });
    ca.Property(x => x.Something, map => map.Length(150));
});

 

It’s flexible (I’m too sexy for my application)

You can organize your mapping as you want, class-by-class, different concerns about a class in different places and so on… (yes!! if you are a ConfORM user you know the concept)

var mapper = new ModelMapper();
mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map =>
    {
        map.Column("MyClassId");
    });
    ca.Id(x => x.Id, map =>
    {
        map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
    });
    ca.Property(x => x.Something);
    ca.Property(x => x.Something, map => map.Length(150));
});

As you can see there is no problem duplicating the declaration of a mapped element and you can even do the same with the whole mapping of a class in two different places:

mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map =>
    {
        map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
    });
    ca.Property(x => x.Something);
});

mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map =>
    {
        map.Column("MyClassId");
    });
    ca.Property(x => x.Something, map => map.Length(150));
});

 

It’s conventions friendly (too sexy by far)

You can apply “democratic” conventions

var mapper = new ModelMapper();

mapper.BeforeMapClass +=
    (mi, t, map) => map.Id(x => x.Column((t.Name+"id").ToUpper()));
mapper.BeforeMapProperty +=
    (mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper());

mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map => { });
    ca.Property(x => x.Something);
});

or you may want “republican” conventions

var mapper = new ModelMapper();

mapper.AfterMapClass +=
    (mi, t, map) => map.Id(x => x.Column((t.Name + "id").ToUpper()));
mapper.AfterMapProperty +=
    (mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper());

mapper.Class<MyClass>(ca =>
{
    ca.Id(x => x.Id, map => map.Column("Whatever"));
    ca.Property(x => x.Something, map => map.Column("Whatever"));
});

NHibernate 3.2 too sexy by far!!!