我正在尝试将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;
}
答案 0 :(得分:0)
有两种解决方法。
尝试使用Dapper.FluentMap
扩展名(NuGet)使其变得更容易。
请参见medium.com post about it。总结信息,首先创建地图:
internal class QueueItemMap : EntityMap<QueueItem>
{
internal QueueItemMap()
{
Map(qi => qi.TypeId).ToColumn("type_id");
}
}
然后在配置服务时将其添加:
FluentMapper.Initialize(config =>
{
config.Add(new QueueItemMap());
});
这应该像往常一样自动映射其他属性,但“ {type_id””列将用于TypeId
成员。
如果您通常希望将multiword_column_name
映射到MultiwordColumName
属性的约定,请使用
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
初始化dapper时。
答案 1 :(得分:0)
我不建议在select语句上使用*,特别是在您希望将结果映射到类型化的类的情况下。
Dapper非常擅长将查询映射到类,而无需映射包,请尝试执行以下操作:
清除所有映射类和调用,
像这样离开班级:
public class QueueItem
{
public long Id { get; }
public string Item { get; }
public int TypeId { get; }
}
并将select语句更改为此:
SELECT `ID` AS ID,
`ITEM` AS ITEM,
`TYPE_ID` AS TYPEID
FROM `QUEUE_ITEMS`
WHERE `PROCESSED_AT` IS NULL AND `COMPLETED_AT` IS NULL ORDER BY `ID` ASC
LIMIT 1;
* Dapper对映射不区分大小写,所以不用担心大小写
如果这不起作用,您可以尝试保留上述更改,而不要这样做
var item = dbConnection.QueryFirst<QueueItem>(sql);
尝试执行此操作,看看错误是否仍然存在:
var item = dbConnection.QueryFirst<dynamic>(sql);
同样,通过使用QueryFirst,您必须假设它会在数据库中找到某些东西,否则它将抛出异常,在这种情况下,您将检查空值,因此请使用QueryFirstOrDefault。
答案 2 :(得分:0)
我发现仅对sql列进行别名以匹配c#名称要容易得多
SELECT
Id,
Item,
type_id as TypeId
...