MsSql Dialect, mapping an nvarchar(max) using string(10000) causes string truncation

Description

In NHibernate 2.1 we were used to map nvarchar(max) columns using something like this:

<property name="propertyname" column="columnname" type="string" length="10000" />

When using SchemaExport() this mapping correctly generates a nvarchar(max) column, but when reading and writing to the column the text is truncated to the size limit of the length specified in the mapping (10k chars in this care): if I try to store a string whose length is 12k chars I get back a 10k chars string.

Using a StringClob mapping and specifying the correct sql-type (like in the following snippet) seems to resolve the problem:

<property name="BlobSqlType" type="StringClob" >
<column name="BlobSqlType" sql-type="nvarchar(max)" />
</property>

Any other combination I've tried doesn't seem to work. This will introduce an unwanted dependency in the mappings and will force us to review all the mappings in our project if we want to switch over to NHibernate 3

Environment

None

Attachments

1

Activity

Julian Maughan March 2, 2011 at 1:07 AM

Matthias, have a look at NH-2484. If this is the issue you are experiencing, it will be fixed in the 3.1 release.

Matthias Otto March 1, 2011 at 10:10 AM

Alessandro, I am experiencing the same problem in 3.0.0.GA running on MSSQL 2008 with a MSSQL 2008 Dialect. The field in question is varchar(max) but the String is truncated after 4000 chars.

The same worked in NHibernate 2.1 without any problems or workaround.

Fabio Maulo's workaround does seems to work but I was wondering if is there is a chance for this to be permanently fixed in 3.1.0.

Thanks for your considerations,

Matt

Fabio Maulo September 1, 2010 at 9:51 AM

Ok workaround found.
"StringClob" by default will generate a nvarcharmax and the value will be truncated at (int.MaxValue / 2).

The workaround fixes even the breaking change of type="string" length=10000

Alessandro Giorgetti September 1, 2010 at 7:19 AM

The 'workaround' is simple and easy, just modify the SqlClinetDriver (or write your custom one) changing the SetVariableLengthParameterSize() function to:

private static void SetVariableLengthParameterSize(IDbDataParameter dbParam, SqlType sqlType)
{
SetDefaultParameterSize(dbParam, sqlType);

// Override the defaults using data from SqlType.
if ((sqlType.LengthDefined) && !(sqlType is StringClobSqlType) && !(sqlType is BinaryBlobSqlType))
{
// we have to take into account a possible varchar or nvarchar (max), so assign the length
// to the string type and to the binary type only if it doesn't exceed the maximum allowed value
// otherwise use the MaxBinaryBlobSize or MaxStringClobSize
if (((sqlType.DbType == DbType.AnsiString) || (sqlType.DbType == DbType.AnsiStringFixedLength))
&& (sqlType.Length > MaxAnsiStringSize))
dbParam.Size = MaxBinaryBlobSize; // I'm not totally sure of this
else if (((sqlType.DbType == DbType.String) || (sqlType.DbType == DbType.StringFixedLength))
&& (sqlType.Length > MaxStringSize))
dbParam.Size = MaxStringClobSize;
else
dbParam.Size = sqlType.Length;
}

if (sqlType.PrecisionDefined)
{
dbParam.Precision = sqlType.Precision;
dbParam.Scale = sqlType.Scale;
}
}

I'm actually using this modified SqlClinetDriver without any issues...I've also tested it against the whole NHibernate Test Suite and all tests passed.
I'll write a blog post about this in the close future too.

Fabio Maulo September 1, 2010 at 5:37 AM

To manage it as we properly, we should add a reference to Microsoft.SqlServer.Management (for example to use SqlDataType.NVarCharMax).
We can't.

We have to found a workaround.

Fixed

Details

Assignee

Reporter

Components

Fix versions

Affects versions

Priority

Who's Looking?

Open Who's Looking?
Created August 23, 2010 at 10:06 AM
Updated August 4, 2017 at 5:52 PM
Resolved September 1, 2010 at 10:16 AM
Who's Looking?