La mejor manera de extraer una relación uno a muchos con dapper dot net orm?

c# dapper one-to-many orm

Pregunta

Tengo dos clases 'Producto' y 'Vendedor'.

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public Seller Seller { get; set; }
    public int? SellerId { get; set; }
}
public class Seller
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Product> Products { get; set; }
}

Quiero extraer una lista de vendedores con todos sus productos usando dapper.

Actualmente lo estoy haciendo así:

Dictionary<int, Seller> dic = new Dictionary<int, Seller>();
        Conn.Query<Seller, Product, int>
            (@"select s.*,p.* from Sellers s Join Products p 
                on p.SellerId = s.Id",
            (s, p) => {
                if (dic.ContainsKey(s.Id))
                    dic[s.Id].Products.Add(p);
                else
                {
                    s.Products = new List<Product>();
                    s.Products.Add(p);
                    dic.Add(s.Id, s);
                }
                return s.Id; 
            });
        var sellers = dic.Select(pair => pair.Value);

¿Hay alguna forma mejor?

Respuesta aceptada

Creo que está mezclando la forma en que desea almacenar los datos con la forma en que desea usarlos. Sugeriría normalizar su base de datos.

//Normalized Database classes
public class Seller
{
    public int Id { get; set; }  // primary key
    public string Name { get; set; }
}

public class Product
{
    public int Id { get; set; }  // primary key
    public int SellerId { get; set; } // foreign key
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Luego puede consultar las tablas de productos y vendedores directamente.

var Sellers = connection.Query<Seller>("Select * from Seller");
var Products = connection.Query<Product>("Select * from Product");

Luego use linq "group by" para lanzar Product en un diccionario

var SellerWithProductsDict = 
        (from prod
        in Products 
        group prod by prod.SellerId
        into groupedProducts
        select groupedProducts)
        .ToDictionary(gp => gp.SellerId, gp => gp.ToList());

A continuación, puede recorrer el SellerWithProductsDict para ver todos los productos del vendedor, y si necesita el nombre del vendedor, simplemente hágalo por índice del resultado de la consulta de Sellers.

**************************************

Ese es el final de la respuesta, pero si realmente necesita mezclar los productos con los vendedores, podría usar la misma estructura de base de datos anterior y hacer algo como:

var qry = @"Select s.Id as SellerId,
                   s.Name as SellerName,
                   p.Id as ProductId,
                   p.Name as ProductName,
                   p.Price as ProductPrice
            From Seller as s, Product as p
            Where s.Id = p.id"

var SellerWithProducts = connection.Query(qry)

Luego use las funciones de linq "group by" para incluir eso en un diccionario. Sugeriría mirar esta publicación " Grupo de Linq por varios campos " para obtener ayuda con el grupo por linq


Respuesta popular

Mi último mensaje se volvió loco por alguna razón.

En primer lugar, podría ser una mala idea obtener todo de su base de datos. Es posible que desee considerar limitar su consulta. A pesar de que su mesa puede ser pequeña ahora, no desea retroceder contra una pared.

Dicho esto, recomendaría simplificar el código para obtener los vendedores y productos agregando métodos estáticos al vendedor y al producto.

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int? SellerId { get; set; }
    public Seller Seller { get; set; }

    public static Product GetProductById(int id)
    {
        Product product = null;
        using (SqlConnection connection = new SqlConnection("connectionString"))
        {
            product = connection.Query<Product>("select * from Product where Id = @Id", new { Id = id }).SingleOrDefault();
            product.Seller = connection.Query<Seller>("select * from Seller where Id = @Id", new { Id = product.SellerId }).SingleOrDefault();
        }

        return product;
    }
}

public class Seller
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Product> Products { get; set; }

    public static Seller GetSellerById(int id)
    {
        Seller seller = null;
        using (SqlConnection connection = new SqlConnection("connectionString"))
        {
            seller = connection.Query<Seller>("select * from Seller where Id = @Id", new { Id = id }).SingleOrDefault();
            if(seller != null)
            {
                seller.Products = connection.Query<Product>("select * from Product where SellerId = @Id", new { Id = id }).ToList();
                seller.Products.ForEach(p => p.Seller = seller);
            }
        }

        return seller;
    }
}

Tenga en cuenta que esto es difícil y no representa todo lo que puede necesitar, pero es más fácil de usar en el largo plazo y sigue el Diseño orientado a objetos mejor que hacer una de las Consultas para obtener sus datos.

Puede ampliar aún más esta idea agregando métodos que busquen otras cosas sobre el vendedor o producto como GetSellersInZipCode (int zipCode) y devuelva una lista a través de ese método.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué