modo migliore per estrarre una relazione uno a molti con dapper dot net orm?

c# dapper one-to-many orm

Domanda

Ho due classi "Prodotto" e "Venditore".

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

Voglio estrarre un elenco di Venditori con tutti i loro prodotti usando dapper.

Attualmente lo sto facendo in questo modo:

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

C'è un modo migliore?

Risposta accettata

Penso che tu stia mescolando come vuoi memorizzare i dati con il modo in cui vuoi usarli. Suggerirei di normalizzare il tuo database.

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

Quindi è possibile interrogare direttamente il venditore e le tabelle dei prodotti.

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

Quindi usa linq "group by" per lanciare Product in un dizionario

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

Quindi puoi scorrere su SellerWithProductsDict per vedere tutti i prodotti del venditore e, se hai bisogno del nome del venditore, procuralo per indice dal risultato della query Venditori

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

Questa è la fine della risposta, ma se davvero hai bisogno che i prodotti si mescolino con i venditori, potresti usare la stessa struttura di database sopra e fare qualcosa del tipo:

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)

Quindi usa le funzioni di linq "group by" per lanciarlo in un dizionario. Suggerirei di guardare questo post " Linq group-by multiple fields " per aiuto con il gruppo di linq


Risposta popolare

Il mio ultimo post è impazzito per qualche motivo.

Prima di tutto, potrebbe essere una cattiva idea ottenere tutto dal tuo database. Potresti prendere in considerazione la possibilità di limitare la tua query. Anche se il tuo tavolo potrebbe essere piccolo ora, non vuoi appoggiarti contro un muro.

Detto questo, consiglierei di semplificare il codice per ottenere i venditori e i prodotti aggiungendo metodi statici a venditore e prodotto.

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

Tieni presente che questo è approssimativo e non rappresenta tutto ciò di cui potresti aver bisogno, ma è più facile da usare a lungo termine e segue il Design orientato agli oggetti meglio di una Query per ottenere i tuoi dati.

È possibile espandere ulteriormente questa idea aggiungendo metodi che richiedono ulteriori informazioni sul venditore o sul prodotto come GetSellersInZipCode (int zipCode) e restituire un elenco tramite tale metodo.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché