meilleure façon d'extraire une relation un à plusieurs avec dapper dot net orm?

c# dapper one-to-many orm

Question

J'ai deux classes 'Produit' et 'Vendeur'.

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

Je veux extraire une liste de vendeurs avec tous leurs produits en utilisant dapper.

Actuellement je le fais comme ceci:

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

Y a-t-il une meilleure façon?

Réponse acceptée

Je pense que vous mélangez la manière dont vous souhaitez stocker les données avec la manière dont vous souhaitez les utiliser. Je suggère de normaliser votre base de données.

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

Ensuite, vous pouvez interroger directement le vendeur et les tables de produits.

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

Ensuite, utilisez linq "group by" pour lancer Product dans un dictionnaire

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

Ensuite, vous pouvez parcourir le SellerWithProductsDict pour voir tous les produits du vendeur, et si vous avez besoin du nom du vendeur, obtenez-le simplement par index à partir du résultat de la requête du vendeur.

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

C'est la fin de la réponse, mais si vous avez vraiment besoin des produits mélangés avec les vendeurs, vous pouvez utiliser la même structure de base de données ci-dessus et faire quelque chose comme:

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)

Ensuite, utilisez les fonctions linq "group by" pour les lancer dans un dictionnaire. Je suggère de regarder ce post " Linq group-by multiple fields " pour de l'aide avec le groupe par linq


Réponse populaire

Mon dernier message est devenu fou pour une raison quelconque.

Tout d'abord, il peut être une mauvaise idée d'obtenir tout de votre base de données. Vous pouvez envisager de limiter votre requête. Même si votre table est peut-être petite maintenant, vous ne voulez pas vous appuyer contre un mur.

Cela étant dit, je recommanderais de simplifier le code pour obtenir les vendeurs et les produits en ajoutant des méthodes statiques au vendeur et au produit.

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

Gardez à l'esprit que ceci est approximatif et ne représente pas tout ce dont vous avez besoin, mais il est plus facile à utiliser à long terme et suit mieux la conception orientée objet que de créer une requête pour obtenir vos données.

Vous pouvez développer davantage cette idée en ajoutant des méthodes qui interrogent d'autres choses sur le vendeur ou le produit, telles que GetSellersInZipCode (int zipCode) et renvoyer une liste via cette méthode.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi