jjzjj

c# - Dapper:映射层次结构和单一不同的属性

coder 2024-05-20 原文

我真的很喜欢 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; }
}

有两个挑战一直困扰着我。

问题 1: 当我只有一个属性差异或简单的枚举/结构映射时,我是否应该始终在 DTO 实体之间创建一个具有映射逻辑的 DTO?

例如:我的 Vendor 实体具有 Balance 属性作为 struct(否则它可能是 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();
}

在这个方法中,我有 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
        };
    }
}

也许你可能会建议我必须将金额和货币存储在一起并像 _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)
};

我能否在没有自己的实现的情况下完成这项工作并节省时间?

问题 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();
}

如您所见,我的问题 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()
    };
}

我想消除许多映射器以防止不必要的工作。

最佳答案

Is there a clean way to retrive & map Order entity with relative properties like Vendor, Item, Category etc)

您没有显示您的 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; 
    });

注意:使用left join,并根据您的表结构进行相应调整。

关于c# - Dapper:映射层次结构和单一不同的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31999144/

有关c# - Dapper:映射层次结构和单一不同的属性的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  5. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  6. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐