DapperLib/DapperAOT

Custom DbType for parameters not working.

ramonesz297 opened this issue · 2 comments

I tried to set DbType using DbValue attribute for parameters and looks like it is not use DbType property

[DapperAot(enabled: true)]
public static class UsersSqlQieries
{
    public sealed class UserIncrementParams
    {
        [DbValue(Name = "userId")]
        public int UserId { get; set; }

        [DbValue(Name = "date", DbType = System.Data.DbType.Date)]
        public DateTime Date { get; set; }
    }

    public static async Task IncrementAsync(DbConnection connection, int userId)
    {
        var date = DateTime.Today;

        await connection.ExecuteAsync("""
            UPDATE [dbo].[table]
            SET [column] = ([column] + 1) 
            WHERE [Id] = @userId and [Date] = @date
            """, new UserIncrementParams() { UserId = userId, Date = date });
    }
}

and generated code:

 file static class DapperGeneratedInterceptors
{
  [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("....cs", 25, 30)]
  internal static global::System.Threading.Tasks.Task<int> ExecuteAsync4(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
  {
      // Execute, Async, HasParameters, Text, KnownParameters
      // takes parameter: global::App.Services.CompiledQueries.Sql.UsersSqlQieries.UserIncrementParams
      // parameter map: Date UserId
      global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql));
      global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text);
      global::System.Diagnostics.Debug.Assert(param is not null);
  
      return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), CommandFactory2.Instance).ExecuteAsync((global::App.Services.CompiledQueries.Sql.UsersSqlQieries.UserIncrementParams)param!);
  
  }
}
  private sealed class CommandFactory2 : global::Dapper.CommandFactory<global::App.Services.CompiledQueries.Sql.UsersSqlQieries.UserIncrementParams>
  {
      internal static readonly CommandFactory2 Instance = new();
      public override void AddParameters(in global::Dapper.UnifiedCommand cmd, global::App.Services.CompiledQueries.Sql.UsersSqlQieries.UserIncrementParams args)
      {
          var ps = cmd.Parameters;
          global::System.Data.Common.DbParameter p;
          p = cmd.CreateParameter();
          p.ParameterName = "userId";
          p.DbType = global::System.Data.DbType.Int32;
          p.Direction = global::System.Data.ParameterDirection.Input;
          p.Value = AsValue(args.UserId);
          ps.Add(p);

          p = cmd.CreateParameter();
          p.ParameterName = "date";
          p.DbType = global::System.Data.DbType.DateTime;  //problem is here, DbType from DbValueAttribute not used 
          p.Direction = global::System.Data.ParameterDirection.Input;
          p.Value = AsValue(args.Date);
          ps.Add(p);

      }
      public override void UpdateParameters(in global::Dapper.UnifiedCommand cmd, global::App.Services.CompiledQueries.Sql.UsersSqlQieries.UserIncrementParams args)
      {
          var ps = cmd.Parameters;
          ps[0].Value = AsValue(args.UserId);
          ps[1].Value = AsValue(args.Date);

      }
      public override bool CanPrepare => true;

  }

As I understood the problem in this method

Should it be?

  public DbType? GetDbType(out string? readerMethod)
        {
            var dbType = IdentifyDbType(CodeType, out readerMethod);
            if (TryGetAttributeValue(_dbValue, "DbType", out int explicitType, out bool isNull))
            {
                var preferredType = isNull ? (DbType?)null : (DbType)explicitType;
                if (preferredType != dbType)
                {   // only preserve the reader method if this matches
                    readerMethod = null;
                    dbType = preferredType; //added line
                }
            }
            return dbType;
        }

fixed next release, thanks; output now (truncated, obviously):

p = cmd.CreateParameter();
p.ParameterName = "date";
p.DbType = global::System.Data.DbType.Date;
p.Direction = global::System.Data.ParameterDirection.Input;
p.Value = AsValue(args.Date);
ps.Add(p);