开发者

Error after upgrading to NHibernate 3.0 XML parsing: line 1, character 4000, unexpected end of input

开发者 https://www.devze.com 2023-02-09 06:35 出处:网络
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 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号