如何使NHibernate停止使用nvarchar(4000)插入参数字符串?

时间:2011-07-08 15:04:50

标签: sql-server hibernate nhibernate fluent-nhibernate nhibernate-mapping

我需要优化域实体上的保存(插入查询)生成的查询。我已经使用Fluent NHibernate配置了NHibernate。

这是NHibernate在插入用户对投票的响应时生成的查询:

exec sp_executesql N'INSERT INTO dbo.Response (ModifiedDate, IpAddress, CountryCode, 
IsRemoteAddr, PollId) VALUES (@p0, @p1, @p2, @p3, @p4); select SCOPE_IDENTITY()',N'@p0
datetime,@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 bit,@p4 int',
@p0='2001-07-08 03:59:05',@p1=N'127.0.0.1',@p2=N'US',@p3=1,@p4=2

如果查看 IpAddress CountryCode 的输入参数,会发现NHibernate正在使用 {{1 }} 即可。问题是nvarchar(4000)nvarchar(4000)IpAddress要大得多,并且由于高流量和托管要求,我需要优化数据库以供内存使用。

以下是这些列的Fluent NHibernate自动映射覆盖:

CountryCode

这不是我看到不必要的nvarchar(4000)弹出的唯一地方。

如何控制 NHibernate 使用 mapping.Map(x => x.IpAddress).CustomSqlType("varchar(15)"); mapping.Map(x => x.CountryCode).CustomSqlType("varchar(6)"); 进行字符串表示?

如何更改此nvarchar(4000)语句以使用适当大小的输入参数?

3 个答案:

答案 0 :(得分:7)

使用TypeNHibernateUtil.AnsiString指定为Length,而不是使用CustomSqlType。

答案 1 :(得分:4)

如果强制SQL Server执行表扫描而不是使用索引,则此问题可能会导致查询出现严重的性能问题。我们在整个数据库中使用varchar,因此我创建了一个全局设置类型的约定:

/// <summary>
/// Convert all string properties to AnsiString (varchar). This does not work with SQL CE.
/// </summary>
public class AnsiStringConvention : IPropertyConventionAcceptance, IPropertyConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.Equals(typeof(string)));
    }

    public void Apply(IPropertyInstance instance)
    {
        instance.CustomType("AnsiString");
    }

}

答案 2 :(得分:2)

好的,我们要做的是,SQLClientDriver忽略了SqlType的长度属性。所以我们创建了一个继承自SQLClientDriver的自己的驱动程序类,并重写方法GenerateCommand ......这样的事情:

public override IDbCommand GenerateCommand(CommandType type, NHibernate.SqlCommand.SqlString sqlString, SqlType[] parameterTypes)
{
    var dbCommand = base.GenerateCommand(type, sqlString, parameterTypes);
    SetParameterSizes(dbCommand.Parameters, parameterTypes);
    return dbCommand;
}

private static void SetParameterSizes(IDataParameterCollection parameters, SqlType[] parameterTypes)
{
    for (int index = 0; index < parameters.Count; ++index)
        SetVariableLengthParameterSize((IDbDataParameter)parameters[index], parameterTypes[index]);
}

private static void SetVariableLengthParameterSize(IDbDataParameter dbParam, SqlType sqlType)
{
    SetDefaultParameterSize(dbParam, sqlType);
    if (sqlType.LengthDefined && !IsText(dbParam, sqlType) && !IsBlob(dbParam, sqlType))
        dbParam.Size = sqlType.Length;
    if (!sqlType.PrecisionDefined)
        return;
    dbParam.Precision = sqlType.Precision;
    dbParam.Scale = sqlType.Scale;
}