diff --git a/Projects/Dotmim.Sync.SqlServer.ChangeTracking/Builders/SqlChangeTrackingBuilderProcedure.cs b/Projects/Dotmim.Sync.SqlServer.ChangeTracking/Builders/SqlChangeTrackingBuilderProcedure.cs index 767718cea..c2d35c169 100644 --- a/Projects/Dotmim.Sync.SqlServer.ChangeTracking/Builders/SqlChangeTrackingBuilderProcedure.cs +++ b/Projects/Dotmim.Sync.SqlServer.ChangeTracking/Builders/SqlChangeTrackingBuilderProcedure.cs @@ -2,11 +2,11 @@ using Dotmim.Sync.SqlServer.Builders; using Dotmim.Sync.SqlServer.Manager; using Microsoft.Data.SqlClient; +using System; using System.Data; using System.Data.Common; using System.Linq; using System.Text; -using static Azure.Core.HttpHeader; namespace Dotmim.Sync.SqlServer.ChangeTracking.Builders { @@ -353,81 +353,7 @@ protected override SqlCommand BuildDeleteCommand() sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; } - - //protected override SqlCommand BuildSelectRowCommand() - //{ - // var sqlCommand = new SqlCommand(); - // this.AddPkColumnParametersToCommand(sqlCommand); - // var sqlParameter = new SqlParameter("@sync_scope_id", SqlDbType.UniqueIdentifier); - // sqlCommand.Parameters.Add(sqlParameter); - - // var stringBuilder1 = new StringBuilder(); - // var stringBuilder11 = new StringBuilder(); - // var stringBuilder3 = new StringBuilder(); - // var stringBuilder4 = new StringBuilder(); - - // string empty = string.Empty; - // string comma = string.Empty; - // foreach (var pkColumn in this.tableDescription.GetPrimaryKeysColumns()) - // { - // var columnName = ParserName.Parse(pkColumn).Quoted().ToString(); - // var parameterName = ParserName.Parse(pkColumn).Unquoted().Normalized().ToString(); - - // stringBuilder1.Append($"{empty}[side].{columnName} = @{parameterName}"); - // stringBuilder11.Append($"{empty}[base].{columnName} = @{parameterName}"); - // stringBuilder3.Append($"{comma}{columnName}"); - // stringBuilder4.Append($"{empty}[base].{columnName} = [side].{columnName}"); - - // empty = " AND "; - // comma = ", "; - // } - - // var stringBuilderColumnsWithSide = new StringBuilder(); - // var stringBuilderColumnsBase = new StringBuilder(); - // foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) - // { - // var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); - - // var isPrimaryKey = this.tableDescription.PrimaryKeys.Any(pkey => mutableColumn.ColumnName.Equals(pkey, SyncGlobalization.DataSourceStringComparison)); - - // if (isPrimaryKey) - // stringBuilderColumnsWithSide.AppendLine($"\t[side].{columnName}, "); - // else - // stringBuilderColumnsWithSide.AppendLine($"\t[base].{columnName}, "); - - // stringBuilderColumnsBase.AppendLine($"\t[base].{ columnName}, "); - // } - - // var stringBuilder = new StringBuilder(); - - // stringBuilder.AppendLine($"IF (SELECT TOP 1 1 FROM CHANGETABLE(CHANGES {tableName.Schema().Quoted().ToString()}, 0) AS [side] WHERE ({stringBuilder1.ToString()})) > 0"); - // stringBuilder.AppendLine("BEGIN"); - // stringBuilder.AppendLine("\tSELECT"); - // // add columns - // stringBuilder.Append(stringBuilderColumnsWithSide.ToString()); - // stringBuilder.AppendLine("\tCAST([side].SYS_CHANGE_CONTEXT as uniqueidentifier) AS [sync_update_scope_id],"); - // stringBuilder.AppendLine("\tCASE [side].SYS_CHANGE_OPERATION WHEN 'D' THEN 1 ELSE 0 END AS [sync_row_is_tombstone]"); - // stringBuilder.AppendLine($"\tFROM CHANGETABLE(CHANGES {tableName.Schema().Quoted().ToString()}, 0) AS [side]"); - // stringBuilder.AppendLine($"\tLEFT JOIN {tableName.Schema().Quoted().ToString()} [base] ON"); - // stringBuilder.AppendLine($"\t\t{stringBuilder4.ToString()}"); - // stringBuilder.AppendLine($"\tWHERE {stringBuilder1.ToString()}"); - // stringBuilder.AppendLine("END"); - // stringBuilder.AppendLine("ELSE"); - // stringBuilder.AppendLine("BEGIN"); - // stringBuilder.AppendLine("\tSELECT"); - // stringBuilder.Append(stringBuilderColumnsBase.ToString()); - // stringBuilder.AppendLine("\tnull as sync_update_scope_id, "); - // stringBuilder.AppendLine("\t0 as sync_row_is_tombstone "); - // stringBuilder.AppendLine($"\tFROM {tableName.Schema().Quoted().ToString()} as [base] "); - // stringBuilder.Append(string.Concat("\tWHERE ", stringBuilder11.ToString())); - // stringBuilder.AppendLine(); - // stringBuilder.AppendLine("END"); - - // sqlCommand.CommandText = stringBuilder.ToString(); - // return sqlCommand; - //} - //------------------------------------------------------------------ // Update command //------------------------------------------------------------------ @@ -598,6 +524,14 @@ protected override SqlCommand BuildSelectInitializedChangesCommand(DbConnection if (filter != null) CreateFilterParameters(sqlCommand, filter); + //Determine if table contains any non-comparable columns (xml, text, ntext) + var mutableColumns = this.tableDescription.GetMutableColumns(false, true).ToArray(); + + //The below types cannot be used in a SELECT DISTICT query unless first converted to an NVARCHAR(MAX) + var nonComparableTypes = new[] { "Xml", "Text", "NText" }; + var nonComparableColumns = mutableColumns.Where(mc => nonComparableTypes.Contains(mc.OriginalDbType, StringComparer.InvariantCultureIgnoreCase)).ToArray(); + var hasNoncomparableColumns = nonComparableColumns.Length > 0; + var stringBuilder = new StringBuilder(""); stringBuilder.AppendLine(";WITH "); stringBuilder.AppendLine($" {trackingName.Quoted()} AS ("); @@ -612,20 +546,33 @@ protected override SqlCommand BuildSelectInitializedChangesCommand(DbConnection stringBuilder.AppendLine("\t[CT].[SYS_CHANGE_VERSION] as [sync_timestamp],"); stringBuilder.AppendLine("\tCASE WHEN [CT].[SYS_CHANGE_OPERATION] = 'D' THEN 1 ELSE 0 END AS [sync_row_is_tombstone]"); stringBuilder.AppendLine($"\tFROM CHANGETABLE(CHANGES {tableName.Schema().Quoted()}, @sync_min_timestamp) AS [CT]"); - stringBuilder.AppendLine("\t)"); + stringBuilder.AppendLine("\t)" + (hasNoncomparableColumns && filter != null ? ", " : "")); // if we have a filter we may have joins that will duplicate lines if (filter != null) - stringBuilder.AppendLine("SELECT DISTINCT "); + { + if (hasNoncomparableColumns) + { + stringBuilder.AppendLine(" DistinctHack AS ("); + } + stringBuilder.AppendLine("SELECT DISTINCT"); + } else - stringBuilder.AppendLine("SELECT "); + stringBuilder.AppendLine("SELECT"); var comma = " "; - foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) + foreach (var mutableColumn in mutableColumns) { var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); - stringBuilder.AppendLine($"\t{comma}[base].{columnName}"); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); + stringBuilder.Append($"\t{comma}"); comma = ", "; + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append($"[base].{columnName}"); + if (isNoncomparable) + stringBuilder.Append($" AS NVARCHAR(MAX)) AS {columnName}"); + stringBuilder.AppendLine(); } stringBuilder.AppendLine($"\t, [side].[sync_row_is_tombstone] as [sync_row_is_tombstone]"); stringBuilder.AppendLine($"FROM {tableName.Schema().Quoted()} [base]"); @@ -677,7 +624,7 @@ protected override SqlCommand BuildSelectInitializedChangesCommand(DbConnection stringBuilder.AppendLine("\t([side].[sync_timestamp] > @sync_min_timestamp OR @sync_min_timestamp IS NULL)"); stringBuilder.AppendLine(")"); - stringBuilder.AppendLine("UNION"); + stringBuilder.AppendLine("UNION ALL"); stringBuilder.AppendLine("SELECT"); comma = " "; foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) @@ -708,8 +655,26 @@ protected override SqlCommand BuildSelectInitializedChangesCommand(DbConnection empty = " AND "; } stringBuilder.AppendLine(); - stringBuilder.AppendLine("WHERE ([side].[sync_timestamp] > @sync_min_timestamp AND [side].[sync_row_is_tombstone] = 1);"); - + stringBuilder.AppendLine("WHERE ([side].[sync_timestamp] > @sync_min_timestamp AND [side].[sync_row_is_tombstone] = 1)"); + if (hasNoncomparableColumns && filter != null) + { + stringBuilder.AppendLine(")"); + stringBuilder.Append("SELECT "); + //Select the distinct values and return them to their original datatype + foreach (var mutableColumn in mutableColumns) + { + var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append(columnName); + if (isNoncomparable) + stringBuilder.Append($" AS {mutableColumn.OriginalDbType}) AS {columnName}"); + stringBuilder.AppendLine(mutableColumn != mutableColumns.Last() ? ", " : ""); + } + stringBuilder.AppendLine("FROM DistinctHack"); + } sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; @@ -732,6 +697,13 @@ protected override SqlCommand BuildSelectIncrementalChangesCommand(SyncFilter fi if (filter != null) CreateFilterParameters(sqlCommand, filter); + //Determine if table contains any non-comparable columns (xml, text, ntext) + var mutableColumns = this.tableDescription.GetMutableColumns(false, true).ToArray(); + + //The below types cannot be used in a SELECT DISTICT query unless first converted to an NVARCHAR(MAX) + var nonComparableTypes = new[] { "Xml", "Text", "NText" }; + var nonComparableColumns = mutableColumns.Where(mc => nonComparableTypes.Contains(mc.OriginalDbType, StringComparer.InvariantCultureIgnoreCase)).ToArray(); + var hasNoncomparableColumns = nonComparableColumns.Length > 0; var stringBuilder = new StringBuilder(""); stringBuilder.AppendLine(";WITH "); stringBuilder.AppendLine($" {trackingName.Quoted().ToString()} AS ("); @@ -751,24 +723,24 @@ protected override SqlCommand BuildSelectIncrementalChangesCommand(SyncFilter fi } stringBuilder.AppendLine($"\n\tFROM CHANGETABLE(CHANGES {tableName.Schema().Quoted().ToString()}, @sync_min_timestamp) AS [CT]"); - stringBuilder.AppendLine("\t)"); + stringBuilder.AppendLine("\t)" + (hasNoncomparableColumns ? "," : "")); - stringBuilder.AppendLine("SELECT DISTINCT"); - //foreach (var pkColumn in this.tableDescription.GetPrimaryKeysColumns()) - //{ - // var columnName = ParserName.Parse(pkColumn).Quoted().ToString(); - // stringBuilder.AppendLine($"\t[side].{columnName},"); - //} - foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) + stringBuilder.AppendLine((hasNoncomparableColumns ? " DistinctHack AS (" : "") + "SELECT DISTINCT"); + foreach (var mutableColumn in mutableColumns) { var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); - + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); var isPrimaryKey = this.tableDescription.PrimaryKeys.Any(pkey => mutableColumn.ColumnName.Equals(pkey, SyncGlobalization.DataSourceStringComparison)); - + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); if (isPrimaryKey) - stringBuilder.AppendLine($"\t[side].{columnName}, "); + stringBuilder.Append($"[side].{columnName}"); else - stringBuilder.AppendLine($"\t[base].{columnName}, "); + stringBuilder.Append($"[base].{columnName}"); + if (isNoncomparable) + stringBuilder.Append($" AS NVARCHAR(MAX)) AS {columnName}"); + stringBuilder.AppendLine(", "); } stringBuilder.AppendLine("\t[side].[sync_row_is_tombstone],"); stringBuilder.AppendLine("\t[side].[sync_update_scope_id]"); @@ -822,24 +794,28 @@ protected override SqlCommand BuildSelectIncrementalChangesCommand(SyncFilter fi stringBuilder.AppendLine("\t[side].[sync_timestamp] > @sync_min_timestamp"); stringBuilder.AppendLine("\tAND ([side].[sync_update_scope_id] <> @sync_scope_id OR [side].[sync_update_scope_id] IS NULL)"); - //if (setupHasTableWithColumns) - //{ - // stringBuilder.AppendLine("\tAND ("); - // string or = string.Empty; - // foreach (var column in this.tableDescription.GetMutableColumns()) - // { - // var unquotedColumn = ParserName.Parse(column).Unquoted().ToString(); - // stringBuilder.Append("\t\t"); - // stringBuilder.Append(or); - // stringBuilder.Append("CHANGE_TRACKING_IS_COLUMN_IN_MASK("); - // stringBuilder.Append($"COLUMNPROPERTY(OBJECT_ID('{tableName.Schema().Quoted().ToString()}'), '{unquotedColumn}', 'ColumnId')"); - // stringBuilder.AppendLine(", [side].[sync_change_columns]) = 1"); - // or = " OR "; - // } - // stringBuilder.AppendLine("\t)"); - //} - stringBuilder.AppendLine(")"); + + if (hasNoncomparableColumns) + { + stringBuilder.AppendLine(")"); + stringBuilder.Append("SELECT "); + //Select the distinct values and return them to their original datatype + foreach (var mutableColumn in mutableColumns) + { + var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append(columnName); + if (isNoncomparable) + stringBuilder.Append($" AS {mutableColumn.OriginalDbType}) AS {columnName}"); + stringBuilder.AppendLine(mutableColumn != mutableColumns.Last() ? ", " : ""); + } + stringBuilder.AppendLine("FROM DistinctHack"); + } + sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; diff --git a/Projects/Dotmim.Sync.SqlServer/Builders/SqlBuilderProcedure.cs b/Projects/Dotmim.Sync.SqlServer/Builders/SqlBuilderProcedure.cs index 96f85feb1..ed6156b19 100644 --- a/Projects/Dotmim.Sync.SqlServer/Builders/SqlBuilderProcedure.cs +++ b/Projects/Dotmim.Sync.SqlServer/Builders/SqlBuilderProcedure.cs @@ -574,7 +574,7 @@ protected virtual SqlCommand BuildResetCommand() sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; } - + public DbCommand CreateResetCommand(DbConnection connection, DbTransaction transaction) { //var commandName = this.sqlObjectNames.GetStoredProcedureCommandName(DbStoredProcedureType.Reset); @@ -1214,25 +1214,34 @@ protected virtual SqlCommand BuildSelectIncrementalChangesCommand(SyncFilter fil if (filter != null) CreateFilterParameters(sqlCommand, filter); - var stringBuilder = new StringBuilder("SELECT DISTINCT"); + //Determine if table contains any non-comparable columns (xml, text, ntext) + var mutableColumns = this.tableDescription.GetMutableColumns(false, true).ToArray(); + + //The below types cannot be used in a SELECT DISTICT query unless first converted to an NVARCHAR(MAX) + var nonComparableTypes = new[] { "Xml", "Text", "NText" }; + var nonComparableColumns = mutableColumns.Where(mc => nonComparableTypes.Contains(mc.OriginalDbType, StringComparer.InvariantCultureIgnoreCase)).ToArray(); + var hasNoncomparableColumns = nonComparableColumns.Length > 0; + + var stringBuilder = new StringBuilder((hasNoncomparableColumns ? "WITH DistinctHack AS (\r\n" : "") + "SELECT DISTINCT"); // ---------------------------------- // Add all columns // ---------------------------------- - //foreach (var pkColumn in this.tableDescription.GetPrimaryKeysColumns()) - //{ - // var columnName = ParserName.Parse(pkColumn).Quoted().ToString(); - // stringBuilder.AppendLine($"\t[side].{columnName}, "); - //} - foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) + foreach (var mutableColumn in mutableColumns) { var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); var isPrimaryKey = this.tableDescription.PrimaryKeys.Any(pkey => mutableColumn.ColumnName.Equals(pkey, SyncGlobalization.DataSourceStringComparison)); - + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); if (isPrimaryKey) - stringBuilder.AppendLine($"\t[side].{columnName}, "); + stringBuilder.Append($"[side].{columnName}"); else - stringBuilder.AppendLine($"\t[base].{columnName}, "); + stringBuilder.Append($"[base].{columnName}"); + if (isNoncomparable) + stringBuilder.Append($" AS NVARCHAR(MAX)) AS {columnName}"); + stringBuilder.AppendLine(", "); } stringBuilder.AppendLine($"\t[side].[sync_row_is_tombstone] as [sync_row_is_tombstone], "); stringBuilder.AppendLine($"\t[side].[update_scope_id] as [sync_update_scope_id]"); @@ -1286,6 +1295,26 @@ protected virtual SqlCommand BuildSelectIncrementalChangesCommand(SyncFilter fil stringBuilder.AppendLine("\tAND ([side].[update_scope_id] <> @sync_scope_id OR [side].[update_scope_id] IS NULL)"); stringBuilder.AppendLine(")"); + if (hasNoncomparableColumns) + { + stringBuilder.AppendLine(")"); + stringBuilder.Append("SELECT "); + //Select the distinct values and return them to their original datatype + foreach (var mutableColumn in mutableColumns) + { + var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append(columnName); + if (isNoncomparable) + stringBuilder.Append($" AS {mutableColumn.OriginalDbType}) AS {columnName}"); + stringBuilder.AppendLine(mutableColumn != mutableColumns.Last()?", ":""); + } + stringBuilder.AppendLine("FROM DistinctHack"); + } + sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; @@ -1320,6 +1349,14 @@ protected virtual SqlCommand BuildSelectInitializedChangesCommand(DbConnection c var pTimestamp = new SqlParameter("@sync_min_timestamp", SqlDbType.BigInt) { Value = "NULL", IsNullable = true }; sqlCommand.Parameters.Add(pTimestamp); + //Determine if table contains any non-comparable columns (xml, text, ntext) + var mutableColumns = this.tableDescription.GetMutableColumns(false, true).ToArray(); + + //The below types cannot be used in a SELECT DISTICT query unless first converted to an NVARCHAR(MAX) + var nonComparableTypes = new[] { "Xml", "Text", "NText" }; + var nonComparableColumns = mutableColumns.Where(mc => nonComparableTypes.Contains(mc.OriginalDbType, StringComparer.InvariantCultureIgnoreCase)).ToArray(); + var hasNoncomparableColumns = nonComparableColumns.Length > 0; + // Add filter parameters if (filter != null) this.CreateFilterParameters(sqlCommand, filter); @@ -1328,7 +1365,11 @@ protected virtual SqlCommand BuildSelectInitializedChangesCommand(DbConnection c // if we have a filter we may have joins that will duplicate lines if (filter != null) - stringBuilder.AppendLine("SELECT DISTINCT "); + { + if (hasNoncomparableColumns) + stringBuilder.AppendLine("WITH DistinctHack AS ("); + stringBuilder.AppendLine("SELECT DISTINCT"); + } else stringBuilder.AppendLine("SELECT "); @@ -1336,8 +1377,15 @@ protected virtual SqlCommand BuildSelectInitializedChangesCommand(DbConnection c foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) { var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); - stringBuilder.AppendLine($"\t{comma}[base].{columnName}"); + stringBuilder.Append($"\t{comma}"); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); comma = ", "; + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append($"[base].{columnName}"); + if (isNoncomparable) + stringBuilder.Append($" AS NVARCHAR(MAX)) AS {columnName}"); + stringBuilder.AppendLine(); } stringBuilder.AppendLine($"\t, [side].[sync_row_is_tombstone] as [sync_row_is_tombstone]"); stringBuilder.AppendLine($"FROM {tableName.Schema().Quoted()} [base]"); @@ -1386,7 +1434,7 @@ protected virtual SqlCommand BuildSelectInitializedChangesCommand(DbConnection c stringBuilder.AppendLine("\t([side].[timestamp] > @sync_min_timestamp OR @sync_min_timestamp IS NULL)"); stringBuilder.AppendLine(")"); - stringBuilder.AppendLine("UNION"); + stringBuilder.AppendLine("UNION ALL"); stringBuilder.AppendLine("SELECT"); comma = " "; foreach (var mutableColumn in this.tableDescription.GetMutableColumns(false, true)) @@ -1417,9 +1465,29 @@ protected virtual SqlCommand BuildSelectInitializedChangesCommand(DbConnection c empty = " AND "; } stringBuilder.AppendLine(); - stringBuilder.AppendLine("WHERE ([side].[timestamp] > @sync_min_timestamp AND [side].[sync_row_is_tombstone] = 1);"); + stringBuilder.AppendLine("WHERE ([side].[timestamp] > @sync_min_timestamp AND [side].[sync_row_is_tombstone] = 1)"); + + if (hasNoncomparableColumns && filter != null) + { + stringBuilder.AppendLine(")"); + stringBuilder.Append("SELECT "); + //Select the distinct values and return them to their original datatype + foreach (var mutableColumn in mutableColumns) + { + var columnName = ParserName.Parse(mutableColumn).Quoted().ToString(); + var isNoncomparable = nonComparableColumns.Contains(mutableColumn); + stringBuilder.Append("\t"); + if (isNoncomparable) + stringBuilder.Append("CAST("); + stringBuilder.Append(columnName); + if (isNoncomparable) + stringBuilder.Append($" AS {mutableColumn.OriginalDbType}) AS {columnName}"); + stringBuilder.AppendLine(mutableColumn != mutableColumns.Last() ? ", " : ""); + } + stringBuilder.AppendLine("FROM DistinctHack"); + } sqlCommand.CommandText = stringBuilder.ToString(); return sqlCommand; diff --git a/Projects/Dotmim.Sync.SqlServer/Builders/SqlDbMetadata.cs b/Projects/Dotmim.Sync.SqlServer/Builders/SqlDbMetadata.cs index cd5158bb8..b08e70716 100644 --- a/Projects/Dotmim.Sync.SqlServer/Builders/SqlDbMetadata.cs +++ b/Projects/Dotmim.Sync.SqlServer/Builders/SqlDbMetadata.cs @@ -41,7 +41,7 @@ public SqlDbMetadata() { } "smallmoney" => DbType.Currency, "nchar" => DbType.StringFixedLength, "numeric" => DbType.VarNumeric, - "nvarchar" => DbType.String, + "nvarchar" => column.MaxLength <= 0 ? DbType.String : DbType.StringFixedLength, "real" => DbType.Decimal, "smalldatetime" => DbType.DateTime, "smallint" => DbType.Int16, @@ -52,8 +52,10 @@ public SqlDbMetadata() { } "tinyint" => DbType.Int16, "uniqueidentifier" => DbType.Guid, "varbinary" => DbType.Binary, - "varchar" => DbType.AnsiString, + "varchar" => column.MaxLength <= 0 ? DbType.AnsiString : DbType.AnsiStringFixedLength, "xml" => DbType.String, + "text" => DbType.String, + "ntext" => DbType.String, _ => throw new Exception($"this type {column.OriginalTypeName} for column {column.ColumnName} is not supported") }; @@ -90,6 +92,8 @@ public SqlDbMetadata() { } "varbinary" => SqlDbType.VarBinary, "varchar" => SqlDbType.VarChar, "xml" => SqlDbType.Xml, + "text" => SqlDbType.Text, + "ntext" => SqlDbType.NText, _ => throw new Exception($"Type '{column.OriginalTypeName.ToLowerInvariant()}' (column {column.ColumnName}) is not supported"), }; @@ -166,6 +170,8 @@ public SqlDbMetadata() { } SqlDbType.VarChar => Type.GetType("System.String"), SqlDbType.Variant => Type.GetType("System.Object"), SqlDbType.Xml => Type.GetType("System.String"), + SqlDbType.Text => Type.GetType("System.String"), + SqlDbType.NText => Type.GetType("System.String"), _ => throw new Exception($"In Column {column.ColumnName}, the type {GetSqlDbType(column)} is not supported"), }; @@ -220,7 +226,7 @@ public override byte GetPrecision(SyncColumn columnDefinition) { "bigint" or "binary" or "bit" or "char" or "date" or "datetime" or "datetime2" or "datetimeoffset" or "decimal" or "float" or "int" or "money" or "nchar" or "numeric" or "nvarchar" or "real" or "smalldatetime" or "smallint" or "smallmoney" - or "sql_variant" or "variant" or "time" or "timestamp" or "tinyint" or "uniqueidentifier" or "varbinary" or "varchar" or "xml" => true, + or "sql_variant" or "variant" or "time" or "timestamp" or "tinyint" or "uniqueidentifier" or "varbinary" or "varchar" or "xml" or "text" or "ntext" => true, _ => false, }; public override bool IsReadonly(SyncColumn columnDefinition) diff --git a/Tests/Dotmim.Sync.Tests/Models/AdventureWorksContext.cs b/Tests/Dotmim.Sync.Tests/Models/AdventureWorksContext.cs index d13902f62..c8c59b27a 100644 --- a/Tests/Dotmim.Sync.Tests/Models/AdventureWorksContext.cs +++ b/Tests/Dotmim.Sync.Tests/Models/AdventureWorksContext.cs @@ -594,6 +594,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { if (this.useSchema) entity.ToTable("SalesOrderHeader", "SalesLT"); + if (this.ProviderType == ProviderType.Sql) + entity.Property(e => e.Comment).HasColumnType("ntext"); entity.HasKey(e => e.SalesOrderId);