Dapper:映射层次结构和单个不同的属性

FSo*_*ou1 16 .net c# dapper

我真的很喜欢Dapper的简约和可能性.我想用Dapper来解决我日常面临的共同挑战.这些描述如下.

这是我的简单模型.

public class OrderItem {
    public long Id { get; set; }
    public Item Item { get; set; }
    public Vendor Vendor { get; set; }
    public Money PurchasePrice { get; set; }
    public Money SellingPrice { get; set; }
}

public class Item
{
    public long Id { get; set; }
    public string Title { get; set; }
    public Category Category { get; set; }
}

public class Category
{
    public long Id { get; set; }
    public string Title { get; set; }
    public long? CategoryId { get; set; }
}

public class Vendor
{
    public long Id { get; set; }
    public string Title { get; set; }
    public Money Balance { get; set; }
    public string SyncValue { get; set; }
}

public struct Money
{
    public string Currency { get; set; }
    public double Amount { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

两个挑战一直困扰着我.

问题1: 在我有单个属性差异或简单的枚举/结构映射的情况下,我是否应该始终在DTO-Entity之间创建具有映射逻辑的DTO?

例如:有我的Vendor实体,它将Balance属性作为结构(否则它可能是Enum).我没有找到比该解决方案更好的东西:

public async Task<Vendor> Load(long id) {
    const string query = @"
        select * from [dbo].[Vendor] where [Id] = @id
    ";

    var row = (await this._db.QueryAsync<LoadVendorRow>(query, new {id})).FirstOrDefault();
    if (row == null) {
        return null;
    }

    return row.Map();
}
Run Code Online (Sandbox Code Playgroud)

在这个方法中,我有2个开销代码:1.我必须创建LoadVendorRow作为DTO对象; 2.我必须在LoadVendorRowVendor之间编写自己的映射:

public static class VendorMapper {
    public static Vendor Map(this LoadVendorRow row) {
        return new Vendor {
            Id = row.Id,
            Title = row.Title,
            Balance = new Money() {Amount = row.Balance, Currency = "RUR"},
            SyncValue = row.SyncValue
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

也许你可能会建议我必须将金额和货币存储在一起并检索它_db.QueryAsync<Vendor, Money, Vendor>(...)- 也许,你是对的.在这种情况下,如果我需要存储/检索Enum(OrderStatus属性),我该怎么办?

var order = new Order
{
    Id = row.Id,
    ExternalOrderId = row.ExternalOrderId,
    CustomerFullName = row.CustomerFullName,
    CustomerAddress = row.CustomerAddress,
    CustomerPhone = row.CustomerPhone,
    Note = row.Note,
    CreatedAtUtc = row.CreatedAtUtc,
    DeliveryPrice = row.DeliveryPrice.ToMoney(),
    OrderStatus = EnumExtensions.ParseEnum<OrderStatus>(row.OrderStatus)
};
Run Code Online (Sandbox Code Playgroud)

我可以在没有自己实现的情况下完成这项工作并节省时间吗

问题2: 如果我想将数据恢复到比简单单级DTO稍微复杂的实体,我该怎么办?OrderItem是很好的例子.这是我现在用来检索它的技术:

public async Task<IList<OrderItem>> Load(long orderId) {
    const string query = @"
            select [oi].*,
                   [i].*,
                   [v].*,
                   [c].*
              from [dbo].[OrderItem] [oi]
              join [dbo].[Item] [i]
                on [oi].[ItemId] = [i].[Id]
              join [dbo].[Category] [c]
                on [i].[CategoryId] = [c].[Id]
              join [dbo].[Vendor] [v]
                on [oi].[VendorId] = [v].[Id]
             where [oi].[OrderId] = @orderId
    ";

    var rows = (await this._db.QueryAsync<LoadOrderItemRow, LoadItemRow, LoadVendorRow, LoadCategoryRow, OrderItem>(query, this.Map, new { orderId }));

    return rows.ToList();
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我的问题1问题迫使我为层次结构中的每个实体编写自定义映射器和DTO.那是我的映射器:

private OrderItem Map(LoadOrderItemRow row, LoadItemRow item, LoadVendorRow vendor, LoadCategoryRow category) {
    return new OrderItem {
        Id = row.Id,
        Item = item.Map(category),
        Vendor = vendor.Map(),
        PurchasePrice = row.PurchasePrice.ToMoney(),
        SellingPrice = row.SellingPrice.ToMoney()
    };
}
Run Code Online (Sandbox Code Playgroud)

我想消除很多地图制作工具以防止不必要的工作.

von*_* v. 9

是否有一种干净的方法来检索和映射Order实体与相关属性,如供应商,项目,类别等)

您没有展示您的Order实体,但我会以您OrderItem为例向您展示您不需要针对特定​​问题的映射工具(如引用的那样).你可以检索OrderItem与沿小号ItemVendor每个通过执行以下的信息:

var sql = @"
select oi.*, i.*, v.* 
from OrderItem 
    inner join Item i on i.Id = oi.ItemId
    left join Vendor v on v.Id = oi.VendorId
    left join Category c on c.Id = i.CategoryId";
var items = connection.Query<OrderItem, Item, Vendor, Category, OrderItem>(sql, 
    (oi,i,v,c)=>
    {
      oi.Item=i;oi.Item.Category=c;oi.Vendor=v;
      oi.Vendor.Balance = new Money { Amount = v.Amount, Currency = v.Currency};
      return oi; 
    });
Run Code Online (Sandbox Code Playgroud)

注意:left join根据您的表格结构使用和调整它.


小智 1

我不确定我是否 100% 理解你的问题。事实上,还没有人试图回答这个问题,这让我相信,当我说这个问题可能有点令人困惑时,我并不孤单。

您提到您喜欢 Dapper 的功能,但我没有看到您在示例中使用它。您是否想开发 Dapper 的替代品?或者您不知道如何在代码中使用 Dapper?

无论如何,这里有一个 Dapper 代码库的链接供您查看: https: //github.com/StackExchange/dapper-dot-net

希望您能解答您的疑问,期待您的回复。