Sql server 控制有关参数的NHIbernate搜索查询输出
当您使用NHibernate“获取”映射对象时,它会向数据库输出一个SELECT查询。它使用参数输出该值;因此,如果我根据租户ID和姓名查询汽车列表,我会得到:Sql server 控制有关参数的NHIbernate搜索查询输出,sql-server,nhibernate,fluent-nhibernate,nhibernate-mapping,Sql Server,Nhibernate,Fluent Nhibernate,Nhibernate Mapping,当您使用NHibernate“获取”映射对象时,它会向数据库输出一个SELECT查询。它使用参数输出该值;因此,如果我根据租户ID和姓名查询汽车列表,我会得到: 从tenantID=@p0和Name=@p1所在的汽车中选择名称、位置 这有一个很好的好处,就是我们的数据库基于这个查询和结果创建(和缓存)一个查询计划,所以当它再次运行时,查询会更快,因为它可以从缓存加载计划 问题是我们是一个多租户数据库,几乎所有的索引都是分区对齐的。我们的租户拥有截然不同的数据集;一个租户可能有5辆车,而另一个租户
从tenantID=@p0和Name=@p1所在的汽车中选择名称、位置
这有一个很好的好处,就是我们的数据库基于这个查询和结果创建(和缓存)一个查询计划,所以当它再次运行时,查询会更快,因为它可以从缓存加载计划
问题是我们是一个多租户数据库,几乎所有的索引都是分区对齐的。我们的租户拥有截然不同的数据集;一个租户可能有5辆车,而另一个租户可能有50000辆。因为NHibernate做到了这一点,我们的数据库为运行它的第一个租户创建和缓存了一个计划。对于运行查询的后续租户,此计划可能没有效率
我想做的是强制NHibernate不要参数化某些参数;即租户ID。因此,我希望查询内容为:
从tenantID=55和Name=@p0的车辆中选择名称、位置
我不知道如何在HBM.XML映射中实现这一点。我如何向NHibernate口述如何使用参数?或者我可以完全关闭参数吗?好了,各位,我想好了 我这样做的方式是用我自己的自定义驱动程序覆盖SqlClientDriver,如下所示:
public class CustomSqlClientDriver : SqlClientDriver
{
private static Regex _partitionKeyReplacer = new Regex(@".PartitionKey=(@p0)", RegexOptions.Compiled);
public override void AdjustCommand(IDbCommand command)
{
var m = _tenantIDReplacer.Match(command.CommandText);
if (!m.Success)
return;
// replace the first parameter with the actual partition key
var parameterName = m.Groups[1].Value;
// find the parameter value
var tenantID = (IDbDataParameter ) command.Parameters[parameterName];
var valueOfTenantID = tenantID.Value;
// now replace the string
command.CommandText = _tenantIDReplacer.Replace(command.CommandText, ".TenantID=" + valueOfTenantID);
}
} }
我重写AdjustCommand方法,并使用正则表达式替换tenantID。这是有效的;不确定是否有更好的方法,但我真的不想打开NHibernate并开始处理核心代码
初始化时,您必须在会话工厂的connection.driver_class属性中注册此自定义驱动程序
希望这对别人有帮助 好了,各位,我知道了 我这样做的方式是用我自己的自定义驱动程序覆盖SqlClientDriver,如下所示:
public class CustomSqlClientDriver : SqlClientDriver
{
private static Regex _partitionKeyReplacer = new Regex(@".PartitionKey=(@p0)", RegexOptions.Compiled);
public override void AdjustCommand(IDbCommand command)
{
var m = _tenantIDReplacer.Match(command.CommandText);
if (!m.Success)
return;
// replace the first parameter with the actual partition key
var parameterName = m.Groups[1].Value;
// find the parameter value
var tenantID = (IDbDataParameter ) command.Parameters[parameterName];
var valueOfTenantID = tenantID.Value;
// now replace the string
command.CommandText = _tenantIDReplacer.Replace(command.CommandText, ".TenantID=" + valueOfTenantID);
}
} }
我重写AdjustCommand方法,并使用正则表达式替换tenantID。这是有效的;不确定是否有更好的方法,但我真的不想打开NHibernate并开始处理核心代码
初始化时,您必须在会话工厂的connection.driver_class属性中注册此自定义驱动程序
希望这对别人有帮助 您也可以使用一个。(从
EmptyInterceptor
派生,重写其OnPrepareStatement
函数,以相同的方式更改sql,打开时在会话中注入sql或在全局配置中定义sql。)也可以使用。(从EmptyInterceptor
派生,重写其OnPrepareStatement
函数,以与更改sql的方式相同的方式更改sql,打开时在会话中注入sql或在全局配置中定义sql。)在我看来,这是一个参数嗅探问题。这通常意味着某些索引缺失或不足。依我看,最好解决这个问题,而不是通过不参数化来回避这个问题。特别是因为SQL Server可能会自动参数化文本。你可以阅读这篇文章来获得更多的信息。在我看来,这是一个参数嗅探问题。这通常意味着某些索引缺失或不足。依我看,最好解决这个问题,而不是通过不参数化来回避这个问题。特别是因为SQL Server可能会自动参数化文本。你可以阅读这篇文章来了解更多的信息。