NHibernate.PropertyValueException: 'Error dehydrating property value'

This things again proved that bug is give your more internal knowledge than any other book.

I used to get error "NHibernate.PropertyValueException: 'Error dehydrating property value' ( For clarity purpose I removed property name). It is part of large product so first I have to identify that how can it be reproduce.

To reproduce I have created one table in sql server with following schema.

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[NewTable](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Text1] [varchar](2000) NULL,
    [Test2] [varchar](50) NULL,
 CONSTRAINT [PK_NewTable] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

C# Code to reproduce.

class Program
    {
        static void Main(string[] args)
        {
            using (var session = NHibernateHelper.OpenSession())
            {

                using (var transaction = session.BeginTransaction())
                {
                    string data = string.Join("", Enumerable.Repeat(1, 4001).ToArray()); ;
                    Console.WriteLine(data.Length);
                    var customer = new NewTable
                    {
                        Text1 = data,
                        Test2 = "text"
                    };

                    session.Save(customer);
                    transaction.Commit();
                }

                Console.ReadKey();
            }
        }
    }

    class NewTable
    {
        public virtual int Id { get; set; }
        public virtual string Text1 { get; set; }
        public virtual string Test2 { get; set; }

    }

    class NewTableMap : ClassMap<NewTable>
    {
        public NewTableMap()
        {
            Id(x => x.Id);
            Map(x => x.Text1).Length(2000).Nullable();
            Map(x => x.Test2).Length(10).Nullable();
            Table("NewTable");
        }
    }

    public class NHibernateHelper
    {

        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    InitializeSessionFactory(); return _sessionFactory;
            }
        }

        private static void InitializeSessionFactory()
        {
            _sessionFactory = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(
            @"<<connection string>>").ShowSql())

         .Mappings(m => m.FluentMappings
         .AddFromAssemblyOf<Program>())
         .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

Let's discuss.

  1. By default when there is any string property in NHibernate , it will default to 4000 length limit. ( It does not consider 2000 character limit at SQL Side)

  2. Now when you try to insert more then 2000 character but less then 4000 character. It will throw following error."SqlException: String or binary data would be truncated." This is true as it is returning from SQL Server. ( In above code instead of 4000 use 3999).

  3. Now when you try to insert more 4000 character , at that time it will hit NHibernate limit of 4000 character and you will receive. 'Error dehydrating property value for <<your property name>>'. This is happen when in Map Length is specified value less then 4000. If it will specify more than 4001 in mapping then it will support large string.

Solution to this would be following. ( Change map for that column).

class NewTableMap : ClassMap<NewTable>
    {
        public NewTableMap()
        {
            Id(x => x.Id);
            //Map(x => x.Text1).Length(2000).Nullable();
            Map(u => u.Text1).CustomType("StringClob").CustomSqlType("varchar(max)").Length(Int32.MaxValue);
            Map(x => x.Test2).Length(10).Nullable();
            Table("NewTable");
        }
    }

Or

class NewTableMap : ClassMap<NewTable>
    {
        public NewTableMap()
        {
            Id(x => x.Id);
            Map(x => x.Text1).Length(4001).Nullable();          
            Map(x => x.Test2).Length(10).Nullable();
            Table("NewTable");
        }
    }

Let me know your comments or suggestion or any other things related to this.