首页 > 解决方案 > 如何将 Dapper QueryFirst 映射到类?

问题描述

我正在尝试将QueryFirst调用映射到该实体,

public class QueueItem
{
    public long Id { get; }
    
    public string Item { get; }
    
    [Column("type_id")]
    public int TypeId { get; }
}

我还设置了这个Column属性来工作,

Dapper.SqlMapper.SetTypeMap(
    typeof(QueueItem),
    new Dapper.CustomPropertyTypeMap(
        typeof(QueueItem),
        (type, columnName) =>
            type.GetProperties().FirstOrDefault(prop =>
                prop.GetCustomAttributes(false)
                    .OfType<ColumnAttribute>()
                    .Any(attr => attr.Name == columnName) || prop.Name == columnName)));

Dapper 抛出一个内部异常,

Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'meth')
   at System.Reflection.Emit.DynamicILGenerator.Emit(OpCode opcode, MethodInfo meth)
   at Dapper.SqlMapper.GenerateDeserializerFromMap(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing, ILGenerator il) in /_/Dapper/SqlMapper.cs:line 3289
   at Dapper.SqlMapper.GetTypeDeserializerImpl(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in /_/Dapper/SqlMapper.cs:line 3075
   at Dapper.SqlMapper.TypeDeserializerCache.GetReader(IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in /_/Dapper/SqlMapper.TypeDeserializerCache.cs:line 153
   at Dapper.SqlMapper.TypeDeserializerCache.GetReader(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in /_/Dapper/SqlMapper.TypeDeserializerCache.cs:line 50
   at Dapper.SqlMapper.GetTypeDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in /_/Dapper/SqlMapper.cs:line 3026
   at Dapper.SqlMapper.GetDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in /_/Dapper/SqlMapper.cs:line 1789
   at Dapper.SqlMapper.QueryRowImpl[T](IDbConnection cnn, Row row, CommandDefinition& command, Type effectiveType) in /_/Dapper/SqlMapper.cs:line 1192
   at Dapper.SqlMapper.QueryFirst[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable`1 commandTimeout, Nullable`1 commandType) in /_/Dapper/SqlMapper.cs:line 741

我尝试Column为所有属性添加属性,结果是一样的。

流畅的映射方法导致相同的异常。

Dapper 初始化(使用流畅的映射):

FluentMapper.Initialize(config =>
{
    config.AddMap(new QueueItemMap());
});

调用 QueryFirst:

public bool TryGetItem(out QueueItem item)
{
    const string sql = @"
            SELECT *
            FROM `queue_items` 
            WHERE `processed_at` IS NULL AND `completed_at` IS NULL ORDER BY `id` ASC
            LIMIT 1;";
    
    using var dbConnection = _dbConnection;
    item = dbConnection.QueryFirst<QueueItem>(sql);
    return item != null;
}

标签: c#dapper

解决方案


我发现为 sql 列设置别名以匹配 c# 名称要容易得多:

SELECT 
  Id,
  Item,
  type_id as TypeId
...

推荐阅读