How does one make NHibernate stop using nvarchar(4000) for insert parameter strings?

后端 未结 4 2043
梦谈多话
梦谈多话 2021-02-14 09:38

I need to optimize a query that is being produced by a save (insert query) on a domain entity. I\'ve configured NHibernate using Fluent NHibernate.

Here\'s the query ge

相关标签:
4条回答
  • 2021-02-14 10:13

    Okay this is what we have to do, the SQLClientDriver ignores the length property of the SqlType. So we created a our own driverclass inheriting from SQLClientDriver and override the method GenerateCommand...Something like this:

    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;
    }
    
    0 讨论(0)
  • 2021-02-14 10:16

    This issue can cause a huge performance problem in queries if it forces SQL Server to perform a table scan instead of using an index. We use varchar throughout our database so I created a convention to set the type globally:

    /// <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");
        }
    
    }
    
    0 讨论(0)
  • 2021-02-14 10:26

    Here is a work around, if you want to replace all nvarchar with varchar

    public class Sql2008NoNVarCharDriver : Sql2008ClientDriver
    {
        public override void AdjustCommand(IDbCommand command)
        {
            foreach (System.Data.SqlClient.SqlParameter x in command.Parameters)
            {
                if (x.SqlDbType == SqlDbType.NVarChar)
                {
                    x.SqlDbType = SqlDbType.VarChar;
                }
            }
            base.AdjustCommand(command);
        }
    }
    

    Then plug it into your config

    var cfg = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString)
                .Driver<Sql2008NoNVarCharDriver>())
                ...
    
    0 讨论(0)
  • 2021-02-14 10:27

    Specify the Type as NHibernateUtil.AnsiString with a Length instead of using a CustomSqlType.

    0 讨论(0)
提交回复
热议问题