Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"No mapping exists" error when using a TypeHandler and a collection parameter #2067

Open
tlecomte opened this issue Apr 3, 2024 · 0 comments · May be fixed by #2068
Open

"No mapping exists" error when using a TypeHandler and a collection parameter #2067

tlecomte opened this issue Apr 3, 2024 · 0 comments · May be fixed by #2068

Comments

@tlecomte
Copy link

tlecomte commented Apr 3, 2024

Dapper is throwing an error when running a query in the following scenario:

  • the parameter is a collection of objects of a given type T
  • and the type T is not natively supported by the SQL client
  • and a TypeHandler is defined for this type T

Example:

// a type that is not natively supported by SqlClient
public struct LocalDate
{
    public int Year { get; set; }
    public int Month { get; set; }
    public int Day { get; set; }
}

// a type handler
public class LocalDateHandler : SqlMapper.TypeHandler<LocalDate>
{
    private LocalDateHandler() { /* private constructor */ }

    // Make the field type ITypeHandler to ensure it cannot be used with SqlMapper.AddTypeHandler<T>(TypeHandler<T>)
    // by mistake.
    public static readonly SqlMapper.ITypeHandler Default = new LocalDateHandler();

    public override LocalDate Parse(object? value)
    {
        var date = (DateTime)value!;
        return new LocalDate { Year = date.Year, Month = date.Month, Day = date.Day };
    }

    public override void SetValue(IDbDataParameter parameter, LocalDate value)
    {
        parameter.DbType = DbType.DateTime;
        parameter.Value = new DateTime(value.Year, value.Month, value.Day);
    }
}

// the failing method
public void RunQueryWithParamCollectionAndCustomTypeHandler()
{
    SqlMapper.AddTypeHandler(typeof(LocalDate), LocalDateHandler.Default);

    var singleParameter = new { SingleDate = new LocalDate { Year = 2014, Month = 7, Day = 25 } };

    // this succeeds
    var resultSingle = connection.Query<int>("SELECT 1 WHERE '2014-07-25' = @SingleDate", singleParameter).Single();

    var parameters = new
    {
        ListOfDates = new List<LocalDate>
        {
            new() { Year = 2014, Month = 7, Day = 25 },
            new() { Year = 2014, Month = 7, Day = 26 },
        }
    };

    // this fails with 'No mapping exists from object type LocalDate to a known managed provider native type.'
    var result = connection.Query<int>("SELECT 1 WHERE '2014-07-25' IN @ListOfDates", parameters).Single();
}
tlecomte pushed a commit to tlecomte/Dapper that referenced this issue Apr 3, 2024
…ameter

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant