简体   繁体   中英

FluentNhibernate - Handle query that refers to a null reference

I tested NHibernate in .net Core and in.Net framework and it seems that requesting a null reference is managed and does not raise a null reference for example by retrieving: x.Property_A.Property_B when Property_A is null.

On another project with a different configuration, this case is not managed and I get a null reference exception if Property_A is null. The versions of nhibernate are the same and the configuration is so huge that I can't find what explains this difference.

Do you have any idea of which configuration could be the cause of this difference?

An overview of the code of the configuration (I can't put everything because it's so large but it's the main thing):

private static ISessionFactory InitializeSessionFactory<T>(bool isAglRebuild = false) where T : ICurrentSessionContext
{
    try
    {
        _configuration = CreateConfiguration();

        FluentConfiguration nhConfig = Fluently.Configure(_configuration)
            .Mappings(m => System.AppDomain.CurrentDomain.GetAssemblies().ToList().ForEach(asm => {
                m.FluentMappings.AddFromAssembly(asm);
                }
                ));

        if (SoNGSettings.isSecondLevelCachingEnabled)
        {
            nhConfig = nhConfig.Cache(x =>
            {
                switch (SoNGSettings.CacheManagerName)
                {
                    default:
                        x.UseSecondLevelCache().ProviderClass<NHCaches.SysCache2.SysCacheProvider>()
                            .UseQueryCache();
                        break;
                }
            });

            if (SoNGSettings.CacheManagerName == Consts.Caching.RedisManager)
            {
                nhConfig.ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.CacheDefaultExpiration, "900"));
                nhConfig.ExposeConfiguration(cfg => cfg.SetProperty("cache.use_sliding_expiration", Boolean.TrueString));
                nhConfig.ExposeConfiguration(cfg => cfg.SetProperty("cache.configuration", SoNGSettings.CacheManagerServerName));
            }
        }
        else
        {
            nhConfig = nhConfig.Cache(x => x.Not.UseSecondLevelCache());
        }

        string version = "";
        if (AppReflection.GetFormBuilderAssembly() != null)
            version = AppReflection.GetFormBuilderAssembly().GetName().Version.ToString();

        var tmpSessionFactory = nhConfig
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.Isolation, "ReadCommitted"))
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.FormatSql, Boolean.TrueString))   //Format the SQL before sending it to the database and Format SQL Queries in Exported Files
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.GenerateStatistics, (SoNGSettings.isNHibernateProfiler ? Boolean.TrueString : Boolean.FalseString))) //   Produce statistics on the number of queries issued, entities obtained, etc
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.Hbm2ddlKeyWords, Hbm2DDLKeyWords.None.ToString())) // Should NHibernate automatically quote all table and column names (ex: [TableName])
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.PrepareSql, Boolean.TrueString))
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.PropertyBytecodeProvider, "lcg")) // What bytecode provider to use for the generation of code (in this case, Lightweight Code Generator)
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.QueryStartupChecking, Boolean.FalseString))// Check all named queries present in the configuration at startup? (none in this example)
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.ShowSql, Boolean.FalseString)) // Show the produced SQL
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.StatementFetchSize, "100")) // The fetch size for resultsets
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.UseProxyValidator, Boolean.FalseString)) // Validate that mapped entities can be used as proxies
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.PropertyUseReflectionOptimizer, Boolean.TrueString))
            //.ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.CacheRegionPrefix, AppReflection.GetFormBuilderAssembly().GetName().Version.ToString()))
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.SessionFactoryName, version))
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.UseSqlComments, Boolean.FalseString)) // Enable the possibility to add SQL comments
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.UseQueryCache, Boolean.TrueString)) // Allows the results of a query to be stored in memory
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.WrapResultSets, Boolean.TrueString)) // Caches internally the position of each column in a resultset
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.BatchSize, "500"))
            .ExposeConfiguration(cfg => cfg.SetProperty(NHCfg.Environment.CommandTimeout, SoNGSettings.DbCommandTimeout.ToString()))
            .ExposeConfiguration(cfg => cfg.SetInterceptor(new ContextInterceptor()));


        ISessionFactory sessionFactory = null;

        if (isAglRebuild)
        {
            TypeFactory.ClearCustomRegistrations();
            sessionFactory = tmpSessionFactory
                                .CurrentSessionContext<T>()
                                .BuildConfiguration()
                                .BuildSessionFactory();

        }
        else
        {
            sessionFactory = tmpSessionFactory
                                .ExposeConfiguration(BuildSchema)
                                .ExposeConfiguration(UpdateSchema)
                                .CurrentSessionContext<T>()
                                .BuildSessionFactory();

            LazyInitializer.AlternativeConstructor(_configuration);

        }

        return sessionFactory;
    }
    catch (Exception ex)
    {
        LoggingFactory.GetLogger().LogError("[NHibernateSessionHelper.InitializeSessionFactory()]", ex);

        throw;
    }
}

private static Configuration CreateConfiguration()
{
    string privateBinPath = BeforeConfiguration();
    MsSqlConfiguration msSqlConfiguration = null;

    msSqlConfiguration = MsSqlConfiguration.MsSql2012
                .ConnectionString(SoNGHelper.GetConnectionString())
                .Dialect<CustomMsSqlDialect>()
                .AdoNetBatchSize(100);

    if (SoNGSettings.isDBShowSql)
    {
        msSqlConfiguration.ShowSql();
    }

    FluentConfiguration fluentConfiguration = Fluently.Configure()
                                                .Database(
                                                    msSqlConfiguration
                                                    );

    if (SoNGSettings.isDBShowDiagnostics)
    {
        CheckFileDirectory(SoNG.Infrastructure.SoNGSettings.DB.DdDirectory,
            SoNG.Infrastructure.SoNGSettings.DB.DbDiagnosticsFile);

        fluentConfiguration.Diagnostics(x => x.Enable().OutputToFile(SoNG.Infrastructure.SoNGSettings.DB.DbDiagnosticsFile));
    }
    else
    {
        fluentConfiguration.Diagnostics(x => x.Disable());
    }

    Configuration configuration = fluentConfiguration.BuildConfiguration();

    AfterConfiguration(privateBinPath);

    return configuration;
}

private static string BeforeConfiguration()
{
    if (!LoggingFactory.IsInitialized())
    {
        log4net.Config.XmlConfigurator.Configure();
    }

    //Backup PrivateBinPath
    string privateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;

    //Erase PrivateBinPath
    AppDomain.CurrentDomain.ClearPrivatePath();
    AppDomain.CurrentDomain.SetupInformation.PrivateBinPath = String.Empty;

    //Add only "bin" path
    AppDomain.CurrentDomain.AppendPrivatePath(AppDomain.CurrentDomain.BaseDirectory + "bin");
    AppDomain.CurrentDomain.SetupInformation.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory + "bin";

    return privateBinPath;
}

private static void AfterConfiguration(string privateBinPath)
{
    //Erase PrivateBinPath
    AppDomain.CurrentDomain.ClearPrivatePath();

    //Add PrivateBinPath backuped
    AppDomain.CurrentDomain.AppendPrivatePath(privateBinPath);
    AppDomain.CurrentDomain.SetupInformation.PrivateBinPath = privateBinPath;
}

Thanks in advance for your help.

EDIT: https://groups.google.com/g/nhibernate-development/c/560IBMajvvw[][1] I found this conversation which confirms me in the idea that nhibernate manages in the select clause the null references but does not understand well the final answer because even if in my mapping I specify that the reference should not be null and that finally it is, nhibernate continues to manage the case correctly into my test solution...

I just understood, in fact, we can write x.Property_A.Property_B when Property_A is null and Property_B is transferred to a nullable type (string for example). However if Property_B is transferred to a non nullable type (int for example) then we will receive the famous null reference exception.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM