Sql server 控制有关参数的NHIbernate搜索查询输出

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辆车,而另一个租户

当您使用NHibernate“获取”映射对象时,它会向数据库输出一个SELECT查询。它使用参数输出该值;因此,如果我根据租户ID和姓名查询汽车列表,我会得到:

从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可能会自动参数化文本。你可以阅读这篇文章来了解更多的信息。