DapperLib / DapperLib/DapperAOT

Enum Invalid cast from 'System.Int64' (works without AOT)

Open
#92 9 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C#
Stars
472
Forks
43
Avg merge
1d 4h
Merged PRs (30d)
18

Description

The following create statement with an Enum in the class will fail with Invalid cast from 'System.Int64'.

I´m using sqlite, the query that fails looks like this

public async Task<long> CreateAsync(AppUser newUser)
{
    await using var connection = new SqliteConnection(settings.ConnectionString);

    const string sql =
        $"""
          INSERT INTO AppUser
          (Username, Password, UserRole) VALUES
          (
            @{nameof(AppUser.Username)},
            @{nameof(AppUser.Password)},
            @{nameof(AppUser.UserRole)}
          ) RETURNING *;
          """;
        
    var insertedRows = await connection.QueryAsync<AppUser>(sql, newUser);

    return insertedRows.FirstOrDefault()?.Id ?? -1;
}

The Enum is mapped to an INTEGER column in Sqlite. Without AOT the mapping works just fine.

Adding a TypeHandler like this does not seem to work either

internal class UserRoleConverter : SqlMapper.TypeHandler<UserRole>
{
    public override UserRole Parse(object value)
    {
        // theoretically this should fix it as casting to enums only works if it´s int32 afaik, but it never gets called
        var int32Value = Convert.ToInt32(value);
        
        return (UserRole) int32Value;
    }

    public override void SetValue(IDbDataParameter parameter, UserRole value)
    {
        parameter.Value = (int)value;
    }
}

// Registered on startup
SqlMapper.AddTypeHandler(new UserRoleConverter());

I am aware that this query in particular parsing the enum would be avoidable entierly, because I only need the Id back, but this would just be a fix for this one query and it would still be an issue for virtual everything else. It just happens to be the first thing that runs in virtually every single test I have.


There is this issue for regular dapper https://github.com/DapperLib/Dapper/issues/259

So, does that mean if dapper AOT does not handle enums out of the box it just won´t be possible to make it work? I could probably work around this with a class that imitates enums and some explicit converters, but I would rather not.


Tried to create a simple wrapper class like this

public class UserRoleColumn(UserRole userRole)
{
    public UserRole Value { get; set; } = userRole;
}

with this type converter

public class UserRoleColumnConverter : SqlMapper.TypeHandler<UserRoleColumn>
{
    public override void SetValue(IDbDataParameter parameter, UserRoleColumn? value)
    {
        ArgumentNullException.ThrowIfNull(value);

        parameter.Value = (int) value.Value;
    }

    public override UserRoleColumn? Parse(object value)
    {
        var userRole = (UserRole) Convert.ToInt32(value);
        return new UserRoleColumn(userRole);
    }
}

Also does not work throws No mapping exists from object type UserRoleColumn to a known managed provider native type in the same place.


On further inspection SqlMapper.AddTypeHandler is not yet AOT friendly. It breaks on publish so wether it´s used or not by the code generated does not even matter because you can´t register them.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the enum INSERT/RETURNING query under AOT publish, then inspect generated mapping and the SqlMapper.AddTypeHandler entry point. Done means SQLite INTEGER enum values map correctly under AOT and type-handler registration does not break publishing.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sqlite
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.