Saturday, November 30, 2013

Typical NHibernate SessionFactory boilerplate

using DomainMapping.Mappings;

using NHibernate.Cfg;


using System.Linq;

using System.Collections.Generic;



namespace DomainMapping
{
    public static class Mapper
    {


        static NHibernate.ISessionFactory _sessionFactory = Mapper.BuildSessionFactory();


        // call this on production
        public static NHibernate.ISessionFactory SessionFactory
        {
            get { return _sessionFactory; }
        }


        // Call this on unit testing, so we can test caching on each test method independently
        public static NHibernate.ISessionFactory BuildSessionFactory(bool useUnitTest = false)
        {
            var mapper = new NHibernate.Mapping.ByCode.ModelMapper();

            mapper.AddMappings
                (
                    typeof(Mapper).Assembly.GetTypes()
                          .Where( x => x.BaseType.IsGenericType
                                       && x.BaseType.GetGenericTypeDefinition()==typeof(NHibernate.Mapping.ByCode.Conformist.ClassMapping<>)) 
                );

            // Or you can manually add the mappings
            // mapper.AddMappings(new[]
            //    {
            //        typeof(PersonMapping)
            //    });


            var cfg = new NHibernate.Cfg.Configuration();

            // .DatabaseIntegration! Y U EXTENSION METHOD?
            cfg.DataBaseIntegration(c =>
            {
                var cs = System.Configuration.ConfigurationManager.ConnectionStrings["TheJunBetConnection"].ConnectionString;

                // SQL Server
                c.Driver<NHibernate.Driver.SqlClientDriver>();
                c.Dialect<NHibernate.Dialect.MsSql2008Dialect>();
                c.ConnectionString = "Server=localhost;Database=TestTheDatabase;Trusted_Connection=True;MultipleActiveResultSets=True";

                // // PostgreSQL
                // c.Driver<NHibernate.Driver.NpgsqlDriver>();
                // c.Dialect<NHibernate.Dialect.PostgreSQLDialect>();
                // c.ConnectionString = "Server=localhost; Database=test_the_database; User=postgres; password=opensesame";                


                if (useUnitTest)
                {
                    c.LogSqlInConsole = true;
                    c.LogFormattedSql = true;
                }
            });

            var domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();


            // // AsString is an extension method from NHibernate.Mapping.ByCode:
            // string mappingXml = domainMapping.AsString();

            // // Life without Resharper. 
            // string mappingXml = NHibernate.Mapping.ByCode.MappingsExtensions.AsString(domainMapping);

            // System.Console.WriteLine(mappingXml);


            cfg.AddMapping(domainMapping);


            // http://www.ienablemuch.com/2013/06/multilingual-and-caching-on-nhibernate.html
            //var filterDef = new NHibernate.Engine.FilterDefinition("lf", /*default condition*/ null,
            //                                                       new Dictionary<string, NHibernate.Type.IType>
            //                                                           {
            //                                                               { "LanguageCultureCode", NHibernate.NHibernateUtil.String}
            //                                                           }, useManyToOne: false);
            //cfg.AddFilterDefinition(filterDef);



            cfg.Cache(x =>
            {
                // SysCache is not stable on unit testing
                if (!useUnitTest)
                {
                    x.Provider<NHibernate.Caches.SysCache.SysCacheProvider>();

                    // I don't know why SysCacheProvider is not stable on simultaneous unit testing, 
                    // might be SysCacheProvider is just giving one session factory, so simultaneous test see each other caches
                    // This solution doesn't work: http://stackoverflow.com/questions/700043/mstest-executing-all-my-tests-simultaneously-breaks-tests-what-to-do                    
                }
                else
                {
                    // This is more stable in unit testing
                    x.Provider<NHibernate.Cache.HashtableCacheProvider>();
                }





                // http://stackoverflow.com/questions/2365234/how-does-query-caching-improves-performance-in-nhibernate

                // Need to be explicitly turned on so the .Cacheable directive on Linq will work:                    
                x.UseQueryCache = true;
            });


            if (useUnitTest)
                cfg.SetInterceptor(new NHSqlInterceptor());

            var sf = cfg.BuildSessionFactory();




            //using (var file = new System.IO.FileStream(@"c:\x\ddl.txt",
            //       System.IO.FileMode.Create,
            //       System.IO.FileAccess.ReadWrite))
            //using (var sw = new System.IO.StreamWriter(file))
            //{
            //    new NHibernate.Tool.hbm2ddl.SchemaUpdate(cfg)
            //        .Execute(scriptAction: sw.Write, doUpdate: false);
            //}

            return sf;
        }

        class NHSqlInterceptor : NHibernate.EmptyInterceptor
        {
            // http://stackoverflow.com/questions/2134565/how-to-configure-fluent-nhibernate-to-output-queries-to-trace-or-debug-instead-o
            public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
            {

                Mapper.NHibernateSQL = sql.ToString();
                return sql;
            }

        }

        public static string NHibernateSQL { get; set; }


    } // Mapper



}



Happy Coding!

Friday, November 22, 2013

Add a condition on joined entities in NHibernate

This query is working, but the cross-cutting concern, e.g., localization, is cluttering the main Where clause

var x = 
    (from q in 
        from ps in session.Query<GetProductSold>()
        join pl in session.Query<ProductLanguage>() on ps.ProductId equals pl.ProductLanguageCompositeKey.ProductId
        select new { ps, pl }
    where q.pl.ProductLanguageCompositeKey.LanguageCode == languageCode
    select q).Cacheable();


We can convert that to following, however NHibernate doesn't support this yet:
var x = 
    (from q in 
         from ps in session.Query<GetProductSold>()
         join pl in session.Query<ProductLanguage>().Where(plc => plc.ProductLanguageCompositeKey.LanguageCode == languageCode) on ps.ProductId equals pl.ProductLanguageCompositeKey.ProductId
         select new { ps, pl }                         
     select q).Cacheable();


We have to do it this way:
var x =
    (from q in
         from ps in session.Query<GetProductSold>()
         join pl in session.Query<ProductLanguage>() on new { ps.ProductId, LanguageCode = languageCode } equals new { pl.ProductLanguageCompositeKey.ProductId, pl.ProductLanguageCompositeKey.LanguageCode }
         select new { ps, pl }                         
     select q).Cacheable();

Saturday, November 2, 2013

Managed code success stories

If you think managed code is slow, think twice

C++ :
million lines of code
40 developers
15 years
output: 10k trades per second

Managed code :
6k lines of code*
1 developer
3 months
output: 200k trades per second

http://stackoverflow.com/questions/4257659/c-sharp-versus-c-performance/19505716#19505716

* Wow! 6k lines of F# code (nope, I'm not cursing lol) only, my thesis is just almost that size. The realization that a 6k lines of code could deliver world-class solution to a world-class problem given using the right tool, just humbled the C++ programmer in me; likewise to my C# skills too


Thoughts on managed language vs C++ on the above success of managed code against C++ :

https://twitter.com/jonharrop/status/392415184045633536


Of course there are more success stories on C++ too :

http://www.computerworlduk.com/news/open-source/3260727/london-stock-exchange-in-historic-linux-go-live/

http://www.computerworlduk.com/in-depth/open-source/3246835/london-stock-exchange-linux-record-breaking-system-faces-new-challengers/


Happy Computing! ツ