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.

60 comments:

  1. I don't understand what is this all about?
    If someone like FNH, he can use it. If someone likes ConfORM - use it. But why fight about which is better?

    ReplyDelete
  2. Fabio, don't listen stupid people.
    You are doing a great job!
    Thanks you a lot!
    Greetings from Ukraine.

    ReplyDelete
  3. Alexey, ты тупой идиот

    ReplyDelete
  4. Alexey is right: why don't we all do what we want and don't bother about what the other is doing? There is room and opportunities for everyone.

    ReplyDelete
  5. Саша, логику включи. А лучше мозг.
    Хамством ты показываешь свой уровень развития и интеллекта.

    ReplyDelete
  6. Alexey, Фабио пытается оправдать свои действия, доказать всем, что его тупая хуйня кому-то нужна. Но это не так. Это изобретение колеса, причем колеса квадратного, которое не поедет. Все, кто держит его сторону - тупые идиоты.

    ReplyDelete
  7. Fabio, will you continue to support ConORM?

    ReplyDelete
  8. Слушай, зачем услажнять себе жизнь? Зачем создавать мапинг на каждый класс? У меня вся модель замалена в одном методе, порядка 70 строчек кода. Такое можно сделать в FNH?

    ReplyDelete
  9. >Такое можно сделать в FNH?
    Конечно, только гораздо удобнее, чем, предложенное здесь, шаманство с лямбдами.

    ReplyDelete
  10. Можешь показать пример?

    ReplyDelete
  11. http://wiki.fluentnhibernate.org/Auto_mapping

    ReplyDelete
  12. По поводу лямбд, это очень удобно к примеру при рефакторинге. В FNH у тебя имена описаны строками. т.е. либо у тебя должно быть куча тестов либо лямбда. если это не так покажи пример.

    ReplyDelete
  13. Ок, доля правды есть. Я FNH глубоко не копал, считаю confORM\"mapping by code" более гибким. Если тебе так сильно не нравится линк и новые фичи юзай FNH. Не нужно наезжать на людей, развивающих проект. Выбор всегда хорошо.

    ReplyDelete
  14. Александр, Фабио никому ничего доказывать не нужно, тем более оправдываться. Он делает хороший продукт, кто-то его использует, кому-то нравится, кто-то нет.
    А вот ты вылез и орешь на всю глотку - какой ты, бля, умный и какие все вокруг идиоты. А ты что сделал для community?
    Жду ответа. Нет ответа - обосрался.

    ReplyDelete
  15. Криворучко Юрий, руки выпрями;) Если ему не нужно ничего доказывать и не нужно оправдываться, то почему он оправдывается и что-то кому-то доказывает?

    ReplyDelete
  16. Alexey, выбор в пользу квадратного колеса - говно.

    ReplyDelete
  17. Шуток по поводу моей фамилии я не слышал со школы. Наталкивает на размышлении об уровне твоего интелекта.

    Да, кстати - обосрался!

    ReplyDelete
  18. Александр. Меня теперь интерисует, потрешь ли ты свой срач?
    Большенство обосранцев так и делают, чтобы в конец не опозориться.

    ReplyDelete
  19. Криворучко Юрий, ищущий, да найдет;) я не Фабио и не собираюсь ничего никому доказывать. И, да, я очень рад, что твой запор прошел и ты наконец-то смог просраться, но мне очень неприятно, что ты пишешь об этом здесь.


    @Fabio: if people opposite to this changes to NH core maybe you should stop, and think about it?

    ReplyDelete
  20. Криворучко Юрий, меня уже порядком подзаебало твое копрофильство. Вытри его, а?
    Вот небольшая часть моего вклада в OSS http://xunitcontrib.codeplex.com/SourceControl/network/Forks/hazzik/xunitcontribR6 но из-за тупых идиотов с NIH syndrome он не попал в основную ветку, и очередной велосипедист изобрел свое квадратное колесо, которое даже не покатилось.

    ReplyDelete
  21. Саша, ты мудак. Не обижайся, но это правда.
    Иди погуляй отсюда. И вообще юзай ADO. Как раз для тебя.

    ReplyDelete
  22. Alexey, если что, мудак - человек с яйцами. Если ты кастрат, то мне тебя жаль.

    Если по существу - NH очень удобная ORM, она мне очень нравится, но последнее время меня раздражают новые квадратные колёса, которые попадают в core, благодаря Фабио.

    ReplyDelete
  23. Fabio, just ignore the people complaining. It's your time and you can do what ever the heck you want with it. If people don't like the new additions to NHibernate, well... don't use them. Is it that hard?.

    Good job to you and all of the NHibernate team!

    ReplyDelete
  24. XreiX, if people dont like changes, probably better do not introduce that changes?

    ReplyDelete
  25. hazzik, I'm more than sure more people than not will appreciate the change.

    ReplyDelete
  26. Александр.
    >> но из-за тупых идиотов с NIH syndrome он не попал в основную ветку
    То есть ничего не сделал.

    ReplyDelete
  27. Криворучко Юрий, сам-то ты что сделал?

    ReplyDelete
  28. Hazzik, as with everything open source, don't like it? Don't use it. The changes won't break what you currently have.

    ReplyDelete
  29. @Rei, I like NH, but i do not like that features, so i have no choice. There is better way - make model-centric configuration with differnet providers like xml, fluent-nh, confORM and other.

    ReplyDelete
  30. hazzik, what part of "You don't HAVE to use that feature" don't you understand?

    ReplyDelete
  31. Саша, мы с Алексеем разработали и запустили MES системы с интеграцией на более чем 7ми крупных заводах пищевой промышленности.
    Я и не претендую на роль активного учасника процесса, это ты претендуешь, я пользователь. И как пользователь скажу: let people make the choice.

    ReplyDelete
  32. Криворучко Юрий, дак что ты сделал для сообщества?

    ReplyDelete
  33. Rei, i do not want to have features that useless for me, let they be in addons or something else.

    ReplyDelete
  34. As stated, they are useless for you, but useful for others, I particularly appreciate not having yet another assembly to have to reference/keep up to date, apart from the fact that it does exactly what it should, configure NHibernate by code.

    ReplyDelete
  35. There is no difference between referencing one or two assemblies.

    ReplyDelete
  36. I think this whole snafu demonstrates that I was barking up the right tree with my posts on using typed xml mappings using Linq To XSD to write your OWN fluent mapping librart.

    Everyone is familiar with xml, and everyone has a different idea of how the fluent interface should look. Give everyone a typed interface to NH mappings that resembles the xml mappings as much as is possible (which is why generation off the xsd is a good approach), and then the Fluent config libraries are just external contrib libraries.

    ReplyDelete
  37. Hazzik,
    Why don't you compile NHibernate yourself without mapping by code? It's easy, just exclude the folder. There is no dependency on it.

    ReplyDelete
  38. @rjperes, maybe I should write my own NHibernate?

    ReplyDelete
  39. @Harry
    What you call Linq To XSD in already there since NH2.0 and the work to let people use it was publisched with NH3.0. Have a look to all claases named Hbm*.

    ReplyDelete
  40. Thanks Fabio, I remember having a look at them before but they weren't quite able to do what I thought they needed to.

    e.g. if you try and replicate the mappings as in
    this example using the NHibernate.Cfg.MappingSchema namespace, you can't achieve as clean a mapping as you can with the LinqToXSD generated library.

    This is because there aren't any typed collections on the HbmMapping object which suggest what can be added as child elements. There are some untyped object[] properties, but it's not very intuitive compared to a List, and you can't use an object initializer with an array.

    With a bit of sugar (or a different generator) that namespace would be a great foundation for all the various fluent libraries people want to use, and the fluent libraries could live outside the main NH project.

    ReplyDelete
  41. @Harry
    Use what fit your needs and let NHibernate's team choose what the team think is good for the project they are working on.
    At each release we have increased the number of downloads and the number of users... we are doing everything possible to kill NHibernate but we are failing.

    ReplyDelete
  42. Hey Fabio, I learned a lot of russian with this post. Thanks.
    Петух в духовке, есть хорошая неделя.

    ReplyDelete
  43. If this new (whatsitcalled, Sexy? :)) API is like ConfORM than it is more flexible than Fluent NHibernate, since FNH doesn't support modification of existing mappings. Also, parsing of hbm.XMLs is hurting my application's startup time, and FNH would make it even worse. That said, I think FNH is nice, and I really support the idea of rewriting it to skip the XML step: in that case, I would use FNH for static mappings (because it's easier) and ConfORM or Sexy for dynamic (because it's more powerful).

    ReplyDelete
  44. Thanks, I found this post very helpful. I'd seen some of the ConfORM posts before but I'd never quite picked up the context. I do like the closeness to the .hbm vocabulary.

    With Mapping By Code forming part of the NH Core, I guess at some point the Reference document will cover it? Which should make adoption on new projects a pretty obvious option.

    ReplyDelete
  45. Fabio,

    ConfORM is simply another GREAT way to mapping aur class

    thanks for ALL

    ReplyDelete
  46. @Alexey
    Yes, at least while ConfORM will have better support to discover implementation patterns and apply mapping-patterns.
    The implementation in NHibernate3.2 is a simplification done to give a public API to avoid XML and a simplified support of "conventions-based" mapping.

    Alexey, for the next time: don't waste your time!
    Just use what fits yours needs and leave people do the same.

    ReplyDelete
  47. @hazzik
    "if people opposite to this changes to NH core maybe you should stop, and think about it?"

    It depend on who are those people. You aren't a good candidate to be listened.

    ReplyDelete
  48. I would like to thank all developers who was involved into NHibernate, FluentNHibernate and ConfORM projects.

    Personally I'm sure that having an alternatives is the best part of open source projects.


    @Fabio

    Thank you for this particular post.

    The most important that I saw in this post that you in general is not against FluentNHibernate project and it's API.

    As far as I understand people just annoys you askin the same questions again and again.

    Moreover, I was really surprised and glad that you made some effort and show the way how FluentNHibernate's DSL could be rewritten in order to use API from ConfORM project.

    Despite the fact that ConfORM in some point looks more complicated for me I really like additional power and flexibility of it's API.

    ConfORM don't dictate the way how I should arrange and organize my mapping code. That is very good.

    Right now I'm using FluentNHibernate in my work but I will definitely will try ConfORM in near near future.

    Thank you again!

    ReplyDelete
  49. @Fabio Maulo
    Sometimes you have to stop, to avoid get a piece of shit like Winamp or ACDSee. They have not stopped.

    ReplyDelete
  50. @Fabio Maulo
    Plz change the settings of your RSS feed to show the full content of the posts. thanks!

    ReplyDelete
  51. I love that people post in all the languages. But Fluent 1.2 is last release of FNH then how I upgrade to nH 3.2? I have other things to do in my project than writing mapping again. Sigh!!! I just started my project and I end up here. What is the situation of other people.

    ReplyDelete
  52. I can't resist to give my opinion about the ongoing discussion about Loquacious and Fluent. (I know it won't stop people from fighting. But I promise to give my opinion only *once* and would appreciate if everyone would follow my example ;-)

    What a shame that some people of Fluent and NH are fighting that much. I know OSS projects which have been killed because of that. *So please stop it now!* There is no reason to fight! Everything is going exactly the way it should.

    The new features here look very generic and powerful, which are important properties of a core feature.

    There is and should be always space for contribution components. Non-core projects have a big advantage: They can be more specific to a certain usage or kind of project. They should make use of that big freedom!

    Many things are just a matter of taste. Once I wrote on stackoverflow: "The terms in the mapping are relational terms. (Fluent tries to "beautify" them a bit which makes it worse IMO. (...))".

    http://stackoverflow.com/questions/3036784/fluent-nhibernate-foreign-key-violation-or-null-values/3037151#3037151

    ReplyDelete
  53. well, the problem is NH team has not the army of article writers such as MS teams. FHN has a good learning resources around the web, but what about this new sexy one?

    ReplyDelete
  54. First I appreciate the effort of NH-Team and Fabio for confORM and mapping-by-code.

    But there is another side of "dont use it if you don't like". I'm in the same position as 'us'. I started with FNH which was the best option in that time and now i'm stuck. It's good to have the choice, but it's also good to dont have to invest a lot of time finding the right choice, or to have to split forces writing code and documentation. That this is a problem is best seen in the lack of documentation for this new sexy way, because many still use FNH and wont/can't write documentation for it.

    My conclusion: there are downsides to create different solutions for the same problem.

    PS: please dont see this as discredit, it's just my view as a User

    ReplyDelete
  55. @Ronald
    In 4 months NH has 50k downloads (sourceforge+nuget). Can you imagine a 80characters line per each download?
    With NHForge we gave a open WIKI and a pretty open blog-space allowing cross posting...
    Around one year we was looking even for a payed guy to write doc...

    PS: please see it just as the point of view from a OSS developer.

    ReplyDelete
  56. @Fabio thanks for the answer.

    However I'm not sure what you mean by "Can you imagine a 80characters line per each download?"

    ReplyDelete
  57. @Roland
    If each one have downloaded NH would contribute a line of documentation we will have a huge book.

    The current on-line reference is composed by 11356 words... even the contribution of just a word per download could be enough.

    That is what I mean.

    ReplyDelete
  58. I am using c#.net and we are using fluent nhibernate. It was fine until i was connecting to a single database. Now in the same project i am suppose to use multiple database, how can this be achieved. Configuration of the fluent nhibernate is lies in web/app.config file. How to specify multiple connection string over there and how to create multiple session factories. Please suggest

    ReplyDelete