-
-
Notifications
You must be signed in to change notification settings - Fork 518
Open
Description
I am trying to use a custom type handler for a collection type.
The problem is that SqlKata.Helper.Flatten(IEnumerable<object> array)
is decomposing my collection type into its parts.
Thereby it creates an invalid query with more values than parameters.
Reproduction code:
using System.Collections;
using System.Data;
using System.Data.SQLite;
using Dapper;
using SqlKata.Compilers;
using SqlKata.Execution;
var sqliteCompiler = new SqliteCompiler();
var connectionStringBuilder = new SQLiteConnectionStringBuilder() { DataSource = ":memory:" };
using var connection = new SQLiteConnection(connectionStringBuilder.ToString());
var db = new QueryFactory(connection, sqliteCompiler);
db.Statement(@"
CREATE TABLE test (
id integer primary key autoincrement,
single blob,
multi blob
);
");
SqlMapper.AddTypeHandler(new SomeTypeHandler());
SqlMapper.AddTypeHandler(new SomeCollectionTypeHandler());
// Ok
db.Query("test")
.Insert(new { single = new SomeSingleObject("Alice") });
//multi type fails, SqlKata.Helper.Flatten public static IEnumerable<object> Flatten(IEnumerable<object> array)
//flattens what is supposed to be one parameter and creates multiple instead because the collection type implements IEnumerable
db.Query("test")
.Insert(new { multi = new SomeCollectionType([new("Alice"), new("Bob")]) });
class SomeSingleObject
{
public SomeSingleObject(string name)
{
Name = name;
}
public string Name { get; set; }
}
class SomeCollectionType : IEnumerable<SomeSingleObject>
{
public SomeCollectionType(SomeSingleObject[] myThings)
{
MyThings = myThings;
}
public SomeSingleObject[] MyThings { get; set; }
public IEnumerator<SomeSingleObject> GetEnumerator()
{
foreach (var thing in MyThings)
yield return thing;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class SomeTypeHandler : SqlMapper.TypeHandler<SomeSingleObject>
{
public override void SetValue(IDbDataParameter parameter, SomeSingleObject value)
{
parameter.DbType = DbType.String;
parameter.Value = value.Name;
}
public override SomeSingleObject Parse(object value)
{
return new SomeSingleObject((string)value);
}
}
class SomeCollectionTypeHandler : SqlMapper.TypeHandler<SomeCollectionType>
{
public override void SetValue(IDbDataParameter parameter, SomeCollectionType value)
{
parameter.DbType = DbType.String;
parameter.Value = string.Join(",", value.MyThings.Select(my => my.Name));
}
public override SomeCollectionType Parse(object value)
{
return new SomeCollectionType(((string)value).Split(",")
.Select(s => new SomeSingleObject(s)).ToArray());
}
}
Metadata
Metadata
Assignees
Labels
No labels