hibernatenhibernatehibernate-mappinghibernate-criteriasessionfactory

How to dynamically add, modify and remove Class Mappings and Entities in existing SessionFactory without rebuilding it?


I’m facing significant challenges with NHibernate in my .NET application, particularly around dynamically creating tables and altering schemas at runtime. My application needs to create millions of tables concurrently and occasionally modify their schemas. Currently, each table creation or schema alteration involves creating new Configuration and SessionFactory instances, leading to severe memory overhead and performance bottlenecks.

What I've Tried:

My Needs: I need a solution to maintain a single SessionFactory instance that supports:

Key Constraints:

I understand that SessionFactory is immutable, but in my scenario, adding newly persistent entities to the existing SessionFactory is preferable to building a new one. Despite my efforts, rebuilding the SessionFactory is costly (e.g., over 6 GB for 50,000 mappers and 12.27 GB for 100,000 mappers).

I am also open to solutions that allow me to perform CRUD operations and utilize ICriteria, ISession, and ITransaction features without a SessionFactory. My implementation heavily relies on ICriteria, so being able to perform these operations without a SessionFactory is also acceptable.

I kindly seek advice on maintaining a single SessionFactory instance to support dynamic schema changes and table creation, ensuring low memory usage and execution time.


Solution

  • I'm not entirely sure about this solution, but it might be helpful for your investigation. The SessionFactory in NHibernate is generally designed to be immutable for certain purposes, such as security and performance. However, if your goal is to add a new model to the SessionFactory without rebuilding it, there is a way to achieve this by making some modifications to the NHibernate source code. One approach could involve adding a method to the Configuration class to integrate the new model into the existing SessionFactory. Additionally, you might need to adjust the SessionFactoryImpl class to allow for the necessary mutability, particularly by modifying certain readonly dictionary properties. This would enable the addition of the new model, handle caching, and set up pre-HQL and ICriteria queries, all without requiring a full rebuild of the SessionFactory.

    Modify Configuration Class

    public ISessionFactory AddMapperInSessionFactory(SessionFactoryImpl sessionFactory, string MapperName)
    {
            // Implement the logic to find the newly added model in the configuration and pass it
            return sessionFactory.AddMapperInSessionFactory(this, mapping, settings, GetInitializedEventListeners(), newmodel);
    }
    

    Modify SessionFactoryImpl Class

    Convert the readonly dictionaries into mutable dictionaries:

    // Original readonly dictionary
    private readonly ConcurrentDictionary<string, CacheBase> _allCacheRegions = new ConcurrentDictionary<string, CacheBase>();
    
    // Modified mutable dictionary
    private IDictionary<string, CacheBase> _allCacheRegions = new ConcurrentDictionary<string, CacheBase>();
    

    Implement the logic to add the new model:

    public ISessionFactory AddMapperInSessionFactory(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners, PersistentClass model, Mapping.Collection collectionmodel = null)
    {
            // Implement logic to integrate the new model, manage caches, and handle ICriteria
            entityPersisters[model.EntityName] = persister;
    
            if (collectionmodel != null)
            {
                collectionPersisters[collectionmodel.Role] = collectionpersister;
            }
    
            // Additional initialization and validation steps
            return this;
    }
    

    Implement these methods in a fully secure manner to ensure the security of the SessionFactory and to meet your performance requirements.