我有一些继承的代码,它们使用 Dapper 将 SQL SELECT 映射到对象中。 SELECT 具有多个同名列(为简洁起见,省略了一些列)。
SELECT
created_timestamp AS CreatedDate,
imported_timestamp AS CreatedDate
FROM Orders
WHERE OrderId = @OrderId
数据分析显示,每条记录仅填充 2 个 CreatedDate 列之一。运行一些测试表明 Dapper 似乎选择了非 NULL CreatedDate。我找不到任何关于 Dapper 如何处理这种情况的文档。我可以依赖 Dapper 始终选择非 NULL 值吗?
Dapper 是(微)ORM,它应该用于数据库 CRUD 操作。
也就是说,您的业务逻辑应该去其他地方。实现非常简单。不要创建具有重复名称的列。使用 dapper 从数据库获取数据,并在其他地方应用您的业务逻辑,例如检查 null 或 else。
//Following is query
SELECT
created_timestamp AS CreatedDate,
imported_timestamp AS ImportedDate
FROM Orders
WHERE OrderId = @OrderId
//Following is your POCO/DTO
public class Order
{
public int OrderId;//or Guid if that suits you
public string CreatedDate;//or DateTime if that suits you
public string ImportedDate;//or DateTime if that suits you
}
//Following is your business logic
Order order = orderService.GetOrder(orderId);
if(order.CreatedDate != null)
//Do something
else if(order.ImportedDate != null)
//Do something else
根据您的研究,即使 Dapper 选择非空列;在未来的版本中可能无法保证这一点。
如果列名相同,它将选择第二个
我知道这是一篇旧文章,但如果有人想知道,有一个解决方法,其中涉及使用 SqlDataReader 并按列索引/顺序手动映射列。 以下是我用来映射某个过程的结果的示例代码,该过程的某些列具有重复的名称:
var resultList = new List<JobInfoModel>();
await using var connection = new SqlConnection(_dbOptions.Value.DbConnectionString);
await connection.OpenAsync(cancellationToken);
using var command = new SqlCommand("JT_JobGet", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@ClientID", clientId);
command.Parameters.AddWithValue("@UserID", userId);
command.Parameters.AddWithValue("@JobID", jobId);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
try
{
var dataItem = new JobInfoModel
{
Id = reader.GetInt32(0),
Oldid = reader.IsDBNull(1) ? null : reader.GetInt32(1),
ClientId = reader.GetInt32(2),
StatusId = reader.GetInt32(3),
SiteId = reader.GetInt32(4),
ContactName = reader.IsDBNull(5) ? null : reader.GetString(5),
ContactNumber = reader.IsDBNull(6) ? null : reader.GetString(6),
ContactEmail = reader.IsDBNull(7) ? null : reader.GetString(7),
Description = reader.GetString(8),
PriorityId = reader.GetInt32(9),
FaultCategoryId = reader.GetInt32(10),
ContractorId = reader.IsDBNull(11) ? null : reader.GetInt32(11),
ScheduledDate = reader.IsDBNull(12) ? null : reader.GetDateTime(12),
JobTypeId = reader.IsDBNull(13) ? null : reader.GetInt32(13),
ContractorEmailed = reader.IsDBNull(14) ? null : reader.GetString(14),
ContractorCalled = reader.IsDBNull(15) ? null : reader.GetString(15),
ContractorAcknowledgedJob = reader.IsDBNull(16) ? null : reader.GetString(16),
ContractorAttended = reader.IsDBNull(17) ? null : reader.GetString(17),
ContractorRef = reader.IsDBNull(18) ? null : reader.GetString(18),
CapexRef = reader.IsDBNull(19) ? null : reader.GetString(19),
RequestedByUserId = reader.IsDBNull(20) ? null : reader.GetInt32(20),
RequestedDate = reader.IsDBNull(21) ? null : reader.GetString(21),
CreatedByUserId = reader.IsDBNull(22) ? null : reader.GetInt32(22),
CreatedDate = reader.IsDBNull(23) ? null : reader.GetDateTime(23)
};
resultList.Add(dataItem);
}
catch (Exception ex)
{
_logger.LogCritical("Failed to map SP result to class {Exception}", ex);
}
}
}
await connection.CloseAsync();
IsDBNull 方法检查列是否可为空,否则在转换为所需类型时如果列值为空,则会抛出异常。
要运行 SQL 查询,您可能需要以这种方式创建读取器:
using var reader = await connection.ExecuteReaderAsync("SELECT created_timestamp AS CreatedDate, imported_timestamp AS CreatedDate FROM Orders WHERE OrderId = @OrderId");