tutorial stored net framework example español c# .net dapper

c# - stored - dapper vs entity framework



Dapper: jerarquía de mapeo y única propiedad diferente (2)

Realmente amo la simplicidad y las posibilidades de Dapper. Me gustaría usar Dapper para resolver los desafíos comunes a los que me enfrento día a día. Estos se describen a continuación.

Aquí está mi modelo simple.

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; } }

Dos desafíos me han estado impidiendo.

Pregunta 1: ¿Debo crear siempre un DTO con lógica de mapeo entre DTO-Entity en los casos en que tengo una única propiedad de diferencia o un mapeo simple enum / struct?

Por ejemplo: está mi entidad de proveedor, que tiene la propiedad Balance como una estructura (de lo contrario, podría ser Enum ). No he encontrado nada mejor que esa solución:

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

En este método tengo 2 códigos de gastos generales: 1. Tengo que crear LoadVendorRow como objeto DTO; 2. Tengo que escribir mi propia asignación entre LoadVendorRow y 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 }; } }

Quizás podría sugerirme que tenga que almacenar la cantidad y la moneda juntos y recuperarlos como _db.QueryAsync<Vendor, Money, Vendor>(...) - Quizás tenga razón. En ese caso, ¿qué debo hacer si necesito almacenar / recuperar Enum (propiedad 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) };

¿Podría hacer este trabajo sin mis propias implementaciones y ahorrar tiempo?

Pregunta 2: ¿Qué debo hacer si me gustaría restaurar datos a entidades que son un poco más complejas que la simple DTO de un solo nivel? OrderItem es un hermoso ejemplo. Esta es la técnica que estoy usando para recuperarla ahora:

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

Como puede ver, el problema de mi pregunta 1 me obliga a escribir asignadores personalizados y DTO para cada entidad en la jerarquía. Ese es mi mapeador:

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

Hay muchos mapeadores que me gustaría eliminar para evitar trabajos innecesarios.


¿Existe una forma clara de recuperar y asignar una entidad de orden con propiedades relativas como proveedor, artículo, categoría, etc.?

No está mostrando su entidad de Order , pero tomaré su artículo de OrderItem como ejemplo y le mostraré que no necesita una herramienta de mapeo para el problema específico (como se indica). Puede recuperar los artículos de OrderItem junto con la información del Item y del Vendor de cada uno haciendo lo siguiente:

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; });

NOTA: El uso de la left join y ajústelo de acuerdo con la estructura de su tabla.


No estoy seguro de entender su pregunta al 100%. Y el hecho de que nadie haya intentado responderlo todavía, me lleva a creer que no estoy solo cuando digo que podría ser un poco confuso.

Mencionas que te encanta la funcionalidad de Dapper, pero no veo que la uses en tus ejemplos. ¿Es que quieres desarrollar una alternativa a Dapper? ¿O que no sabes cómo usar Dapper en tu código?

En cualquier caso, aquí hay un enlace a la base del código de Dapper para su revisión: https://github.com/StackExchange/dapper-dot-net

Esperando poder aclarar sus preguntas, espero su respuesta.