Skip to content

Commit da6a2ef

Browse files
committed
fix(TypeHandler): use the custom type handler when packing a list parameter
Fixes DapperLib#2067 The code for `SqlMapper.PackListParameters` was not using the custom type handler. This caused an error like `No mapping exists from object type xxxxx to a known managed provider native type.` when passing a collection parameter to a query, when the type of the collection items is not natively supported by the SQL client, and when a custom `TypeHandler` is registered for it. Here this is fixed by using the same logic that is already in `DynamicParameters.AddParameter`. A unit test is added to cover the scenario.
1 parent 402f20c commit da6a2ef

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

Dapper/SqlMapper.cs

+16-6
Original file line numberDiff line numberDiff line change
@@ -2168,6 +2168,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
21682168
if (list is not null && !viaSplit)
21692169
{
21702170
object? lastValue = null;
2171+
SqlMapper.ITypeHandler? handler = null;
21712172
foreach (var item in list)
21722173
{
21732174
if (++count == 1) // first item: fetch some type info
@@ -2178,7 +2179,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
21782179
}
21792180
if (!isDbString)
21802181
{
2181-
dbType = LookupDbType(item.GetType(), "", true, out var handler);
2182+
dbType = LookupDbType(item.GetType(), "", true, out handler);
21822183
}
21832184
}
21842185
var nextName = namePrefix + count.ToString();
@@ -2199,14 +2200,23 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
21992200
}
22002201
}
22012202

2202-
var tmp = listParam.Value = SanitizeParameterValue(item);
2203-
if (tmp is not null && tmp is not DBNull)
2204-
lastValue = tmp; // only interested in non-trivial values for padding
2203+
if (handler is null)
2204+
{
2205+
var tmp = listParam.Value = SanitizeParameterValue(item);
2206+
if (tmp is not null && tmp is not DBNull)
2207+
lastValue = tmp; // only interested in non-trivial values for padding
22052208

2206-
if (DynamicParameters.ShouldSetDbType(dbType) && listParam.DbType != dbType.GetValueOrDefault())
2209+
if (DynamicParameters.ShouldSetDbType(dbType) && listParam.DbType != dbType.GetValueOrDefault())
2210+
{
2211+
listParam.DbType = dbType.GetValueOrDefault();
2212+
}
2213+
}
2214+
else
22072215
{
2208-
listParam.DbType = dbType.GetValueOrDefault();
2216+
if (DynamicParameters.ShouldSetDbType(dbType)) listParam.DbType = dbType.GetValueOrDefault();
2217+
handler.SetValue(listParam, item ?? DBNull.Value);
22092218
}
2219+
22102220
command.Parameters.Add(listParam);
22112221
}
22122222
}

tests/Dapper.Tests/TypeHandlerTests.cs

+18
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,24 @@ public void SO24740733_TestCustomValueSingleColumn()
425425
Assert.Equal(200, foo.Value);
426426
}
427427

428+
[Fact]
429+
public void Issue2067_TestCustomValueCollection()
430+
{
431+
SqlMapper.AddTypeHandler(RatingValueHandler.Default);
432+
433+
var parameters = new
434+
{
435+
ListOfRatingValues = new List<RatingValue>
436+
{
437+
new() { Value = 1 },
438+
new() { Value = 2 },
439+
}
440+
};
441+
442+
var result = connection.Query<int>("SELECT 1 WHERE 1 IN @ListOfRatingValues", parameters).Single();
443+
Assert.Equal(1, result);
444+
}
445+
428446
public class StringListTypeHandler : SqlMapper.TypeHandler<List<string>>
429447
{
430448
private StringListTypeHandler()

0 commit comments

Comments
 (0)