我真的很喜欢 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. 我必须自己编写 LoadVendorRow 和 Vendor 之间的映射:
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 以及每个的 Item 和 Vendor 信息:
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/
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我希望我的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
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个具有一些属性的模型: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
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.