Error after upgrading to NHibernate 3.0 XML parsing: line 1, character 4000, unexpected end of input
I have a sql2008 db that has a column type of xml. Using NHibernate 2.5 I can save to this column no problems.
I've dropped in the NHibernate 3.0 dlls and suddenly I'm getting the above errors?
My mapping file doesn't have a type against that column so surely NHibernate should pick up the xml data type (I'm using the sql 2008 dialect) ?
4000 just seems to be a suspicious length, i.e the length of a varchar column in sql.
I see there are a few articles about mapping xml columns using custom UserTypes, etc.
How come this just worked in 2.5 and now doesn't in 3.0 ? I don't need any special handling. That column gets used as a strin开发者_开发问答g everywhere.
The reason this behavior changed from 2.x to 3.0.0 was due to a code commit on NHibernate.Driver.SqlClientDriver
, which effectively turned on some of the behavior of enabling the prepare_sql
configuration in order to resolve an issue with the caching of query plans.
A C# string
property mapped to a column that has no other type
specified in its mapping will get treated as a NHibernate.SqlTypes.StringSqlType
and given a 4000 character limit by the driver:
From NHibernate.SqlTypes.StringSqlType
:
/// <remarks> /// This can store the length of the string that the <see cref="IDbDataParameter"/> can hold. /// If no value is provided for the length then the <c>Driver</c> is responsible for /// setting the properties on the <see cref="IDbDataParameter"/> correctly. /// </remarks>
So, you can see that the code below from the driver (NHibernate.Driver.SqlClientDriver
), maps a default string
property to a length of 4000 characters.
/* SNIP */
private const int MaxAnsiStringSize = 8000;
private const int MaxBinarySize = MaxAnsiStringSize;
private const int MaxStringSize = MaxAnsiStringSize / 2;
private const int MaxBinaryBlobSize = int.MaxValue;
private const int MaxStringClobSize = MaxBinaryBlobSize / 2;
/* SNIP */
private static void SetDefaultParameterSize(IDbDataParameter dbParam, SqlType sqlType)
{
switch (dbParam.DbType)
{
/* SNIP */
case DbType.String:
case DbType.StringFixedLength:
dbParam.Size = IsText(dbParam, sqlType) ? MaxStringClobSize : MaxStringSize;
break;
/* SNIP */
}
}
For configurations with prepare_sql
set to false
, NH 3.0.0 now brings the SetDefaultParameterSize
method into play where it was not before
As you noted, you can use NH-3.0.0-native support for the SQL Server XML
datatype (thanks to NH-866), like so:
<property name="Data" type="xml" not-null="true" />
or more explicitly, but equivalently:
<property name="Data" type="XmlDoc" not-null="true">
<column name="DATA" sql-type="XmlSql" />
</property>
But using NHibernate.Type.XmlDocType
expects the property type to be of C# type XmlDocument
- leading to a cast exception.
You could do the XmlDocument.InnerXml
fix like you mentioned, but that's a lot of unnecessary transformation from string to doc and back. I've used the following mapping to keep the domain property a string:
<property name="Data" type="StringClob" not-null="true">
<column name="DATA" sql-type="XmlSql" />
</property>
Using NHibernate.Type.StringClobType
will return true for the IsText(dbParam, sqlType)
call in the driver snippet above, giving a max character length of int.MaxValue / 2
- something like 2GB of string data.
I solved this by changing the property type to xml in the mapping file.
Then just used the XmlDocument that is returned as XmlDocument.InnerXml to get the string value.
精彩评论