question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SqlServer nvarchar(max) AddScalarType

See original GitHub issue

Hi! Linq2db generate invalid SQL for user type (registered with AddScalarType function) columns with db type ‘nvarchar(max)’ ( Parameter Length is 4000 ) User Type:

    [Serializable]
    public class UserType: IConvertible
    {
        public string StringProperty{ get; set; }

        public int IntProperty{ get; set; }

        public UserType()
        {
        }

        public UserType(string stringProperty, int intProperty)
        {
            this.StringProperty = stringProperty;
            this.IntProperty    = intProperty;
        }

        public static UserType CreateFromString(string xml)
        {
            if(string.IsNullOrEmpty(xml))
            {
                return null;
            }

            var reader = new XmlSerializer(typeof(UserType));
            using(var sr = new StringReader(xml))
            {
               
                return (UserType)reader.Deserialize(sr);;
            }
        }

        public static string ConvertToString(UserType item)
        {
            if(item == null)
            {
                return null;
            }

            var writer = new XmlSerializer(typeof(UserType));

            var sb = new StringBuilder();
            using(var sw = new StringWriter(sb, CultureInfo.InvariantCulture))
            {
                using(var xw = XmlWriter.Create(sw, new XmlWriterSettings(){OmitXmlDeclaration = true,NewLineHandling =NewLineHandling.Entitize,Indent =false}))
                {
                    var ns = new XmlSerializerNamespaces();
                    ns.Add(string.Empty, string.Empty);

                    writer.Serialize(xw, item, ns);
                    return sb.ToString();
                }
            }
        }

      

        string IConvertible.ToString(IFormatProvider provider)
        {
            var str = ConvertToString(this);

            return str;
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            if(conversionType == typeof(string))
            {
                var str = ConvertToString(this);

                return str;
            }

            return Convert.ChangeType(this, conversionType, provider);;
        }

          TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            throw new NotImplementedException();
        }
    }

Table Class:

 [Table(Name = "Table1")]
    public class Table1
    {
        [Column(DataType = DataType.Int32)]
        [PrimaryKey]
        [Identity]
        public int Id{ get; set; }

        [Column(CanBeNull = true, DataType = DataType.NVarChar, Length = int.MaxValue)]
        [Nullable]
        public UserType UserTypeColumn{ get; set; }
    }

Connection Class:

 public class TestDbConnection: DataConnection
    {
        static TestDbConnection()
        {
            var mapping = MappingSchema.Default;
            mapping.AddScalarType(typeof(UserType), DataType.NVarChar);
            mapping.SetConvertExpression<string, UserType>(arg => UserType.CreateFromString(arg));
            mapping.SetConvertExpression<UserType,string>(arg => UserType.ConvertToString(arg));
        }

        public TestDbConnection()
                : base(SqlServerTools.GetDataProvider(SqlServerVersion.v2012), GetConnectionString())
        {
            TurnTraceSwitchOn();
            WriteTraceLine = this.WriteSql;

        }

        private void WriteSql(string arg1, string arg2)
        {
            Debug.WriteLine(arg1, arg2);
        }

       

        public ITable<Table1> Table1{ get{ return this.GetTable<Table1>(); } }

        private static string GetConnectionString()
        {
            // return you connection string
        }
    }

Test Project:

class Program
    {
        

        static void Main(string[] args)
        {
            try
            {

                using(var connection = new TestDbConnection())
                {

                    
                    var value1 = new UserType(new string('0',10),1);
                    connection.Table1.Insert(() =>new Table1() { UserTypeColumn = value1});

                    var value2 = connection.Table1.OrderByDescending(table1 => table1.Id).Select(table1 => table1.UserTypeColumn).First();

                    Debug.Assert(value1.IntProperty==value2.IntProperty);
                    Debug.Assert(value1.StringProperty==value2.StringProperty);

                    Console.WriteLine("Test1 passed...");

                    value1 = new UserType(new string('0',4001),1);
                    connection.Table1.Insert(() =>new Table1() { UserTypeColumn = value1});

                    value2 = connection.Table1.OrderByDescending(table1 => table1.Id).Select(table1 => table1.UserTypeColumn).First();

                    Debug.Assert(value1.IntProperty==value2.IntProperty);
                    Debug.Assert(value1.StringProperty==value2.StringProperty);

                    Console.WriteLine("Test2 passed...");

                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            Console.WriteLine("Press any key...");
            Console.ReadKey(false);
        }
    }

Debug Output:

– SqlServer.2012 DECLARE @value1 NVarChar(4000) – String <— always 4000! SET @value1 = linq2dbTest.UserType <— better show result from Convert function!

INSERT INTO [Table1] ( [UserTypeColumn] ) VALUES ( @value1 )

Thank you!!!

Environment details

linq2db version: 2.6.3 Database Server: MS Sql Server 2017 Framework version: .NET Framework 4.6.1

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
Kalina9001commented, Jan 23, 2019

if (value is string strValue && strValue.Length > 4000)

strValue is null because value is UserType

0reactions
Kalina9001commented, Mar 4, 2019

Thank you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

What is the maximum characters for the NVARCHAR(MAX)?
The max size for a column of type NVARCHAR(MAX) is 2 GByte of storage. Since NVARCHAR uses 2 bytes per character, that's approx....
Read more >
nchar and nvarchar (Transact-SQL) - SQL Server
max indicates that the maximum storage size is 2^31-1 characters (2 GB). The storage size is two times n bytes + 2 bytes....
Read more >
SQL NVARCHAR(Max) Data Type
The NVARCHAR(Max) data type stores variable-length character strings. NVARCHAR(Max) is used to store very large character data. NVARCHAR(Max) can hold as much ...
Read more >
Comparing VARCHAR(max) vs VARCHAR(n) data types in ...
This article gives an overview of varchar(max) data type and its comparison with the varchar(n) data type.
Read more >
NVARCHAR(MAX) string appears to have 6326 characters ...
1 Answer 1 ... This is a limitation of what can be displayed in the "Messages" tab via either PRINT or RAISERROR ....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found