-
Notifications
You must be signed in to change notification settings - Fork 131
Description
Bug Description
Preconditions
- A table with a primary key field of type
[N][VAR]CHARand a length exceeding 30 characters. - Models to insert into the table, containing ID values that also exceed this limit.
Faulty behavior
After executing any overload of SqlConnection.Insert[All][Async], the models' field values are truncated to 30 characters.
Reason
Internally, the library executes a query containing SELECT CONVERT(NVARCHAR, @IdField) and assigns the result to the model's ID field.
Since the default length for [N][VAR]CHAR when casting or converting is 30, characters beyond that are cut off.
"If n isn't specified when using the CAST and CONVERT functions, the default length is 30."
"When n isn't specified with the CAST function, the default length is 30."
Even though the latter quote does not mention CONVERT, the same behavior can be observed for all four data types.
Circumvention
Perform any required setup before inserting the models.
The bug only has an impact if the models are reused after the insert operation.
Proposed simple solution for variable-size string data
Add MAX as the string size for [N]VARCHAR, changing three lines in RepoDb.Resolvers.DbTypeToSqlServerStringNameResolver.Resolve(DbType):
DbType.String => "NVARCHAR(MAX)",DbType.AnsiString => "VARCHAR(MAX)",_ => "NVARCHAR(MAX)",
This cannot be applied to [N]CHAR, as MAX is not allowed for fixed-size string data.
Proposed solution
Set the string size in the above locations based on the database schema and/or the model's [Size(n)] attribute instead of using MAX.
RepoDb.DbField.Size currently reflects the value from [sys].[columns].[max_length] (which is twice the string length; the correct value could be retrieved from [INFORMATION_SCHEMA].[COLUMNS].[CHARACTER_MAXIMUM_LENGTH]).
However, this value is dismissed on the way to constructing the insert statement.
Schema and Model:
CREATE TABLE [dbo].[NVarCharTable] (
[Id] NVARCHAR(36) NOT NULL,
[Value] NVARCHAR(36) NULL,
CONSTRAINT [PK_NVarCharTable] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
) ON [PRIMARY]public record StringPkTable
{
//[Size(36)]
public string Id { get; init; } = string.Empty;
public string Value { get; init; } = string.Empty;
public int IdLength => Id.Length;
public int ValueLength => Value.Length;
}Library Version:
RepoDb v1.13.1 and RepoDb.SqlServer v1.13.1