Мне очень нравится простота и возможности Даппера. Я хотел бы использовать 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-Сущности в тех случаях, когда у меня есть разница одного свойства или простое перечисление отображение/STRUCT?
Например: Существует мой Vendor объект, который имеет Баланс свойство как структуры (в противном случае он может быть 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 property)?
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()
};
}
Есть много картографов, которые я хотел бы устранить, чтобы предотвратить ненужную работу.
Вы пытались использовать что-то вроде [AutoMapper] (http://automapper.org/) или [ValueInjecter] (https://valueinjecter.codeplex.com/), чтобы автоматически сопоставлять объекты или вы не хотите использовать какие-либо картографы? – pasty
Вы загружаете данные из db в 'LoadVendorRow' и имеете поле' Balance'. Так что же это на самом деле в вашей таблице «Продавец»? Имеются ли в нем поля «Валюта и сумма»? Поле Balance совпадает с полем Amount в вашем db? Также кажется, что каждый раз, когда есть поле «деньги/стоимость», вы конвертируете его в свою структуру «Деньги». Так всегда есть поля «деньги + валюта» в вашей БД? Например, DeliveryPrice и DeliveryPriceCurrency? –
@pasty, нет, я не пробовал, но должен ли он дать мне какие-нибудь льготы? – FSou1