[英]FluentNhibernate - Handle query that refers to a null reference
我在 .net Core 和 in.Net 框架中測試了 NHibernate,似乎請求 null 引用是受管理的,並且不會引發 null 引用,例如通過檢索:x.Property_A.Property_B 當 Property_A 為 null 時。
在另一個具有不同配置的項目中,這種情況不受管理,如果 Property_A 是 null,我會得到一個 null 引用異常。nhibernate 的版本是相同的,配置是如此之大,以至於我找不到解釋這種差異的原因。
您知道哪種配置可能是造成這種差異的原因嗎?
配置代碼的概述(我不能把所有的東西都放上去,因為它太大了,但它是主要的):
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;
}
在此先感謝您的幫助。
編輯: https://groups.google.com/g/nhibernate-development/c/560IBMajvvw[][1]我發現這個對話證實了我的想法,即 nhibernate 在 select 子句中管理 null 引用但不理解好吧,最后的答案是因為即使在我的映射中我指定引用不應該是 null 並且最終它是,nhibernate 繼續將案例正確地管理到我的測試解決方案中......
剛剛明白,其實我們可以寫x.Property_A.Property_B,當Property_A為null,Property_B轉為可空類型(例如string)。 但是,如果 Property_B 被轉換為不可空類型(例如 int),那么我們將收到著名的 null 引用異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.