¿Cómo puedo mapear múltiples listas con dapper?

c# dapper nested orm sql

Pregunta

Tengo tres clases Usuario, Orden y Proyecto que están almacenadas en tablas individuales. Los pedidos y proyectos tienen una relación an: n con los usuarios. Para implementar eso, tengo dos tablas cruzadas (UserOrders, UserProjects) que mapean estas relaciones.

public class User
{
  public string UserID {get;set;}
  public List<string> Orders{get;set;}
  public List<string> Projects {get;set;}
}

public class Order
{
  public string OrderID {get;set}
  ...
}

public class Project
{
  public string ProjectID {get;set}
  ...
}

Como puede ver, el objeto Usuario contiene una lista de cada orderID / projectID relacionado.

Ahora quiero consultar esto con Dapper. Tengo esta solución que funciona bastante bien con una sola lista. Pero si trato de consultar el objeto de usuario completo para la segunda lista, obtendré multiplicado cada resultado por el número de resultados en la primera lista. Entonces, si un usuario recibe 3 pedidos y 2 proyectos, la lista de pedidos estará bien y la lista de proyectos contendrá los 3 proyectos 3 veces:

var lookup = new Dictionary<string, User>();
var multi = dbDapperFM.Query<User, string, string, User>("SELECT u.*, uo.OrderID, up.ProjectID "+
        "FROM User u INNER JOIN UserOrders uo ON u.UserID=uo.UserID "+
        "INNER JOIN UserProjects up ON u.UserID=up.UserID", (u, uo, up) =>
    {
      User user;
      if (!lookup.TryGetValue(m.UserID, out user))
          lookup.Add(u.UserID, user= u);

      if (user.Orders == null)
          user.Orders = new List<string>();
      user.Orders.Add(uo);

      if (user.Projects == null)
          user.Projects = new List<string>();
      user.Projects.Add(up);
      return user;
    }, splitOn: "UserID , OrderID, ProjectID ").AsQueryable();

Entiendo por qué se produce este problema (2 combinaciones internas), pero realmente no entiendo cómo resolverlo.

Respuesta aceptada

También tuve problemas para entender el hecho de que Dapper no hace esto automáticamente.

Primero, no estoy seguro acerca de los valores separados por comas para "splitOn". Pensé que solo podrías tener un valor allí. Así que tengo varias columnas en mi conjunto de resultados llamado "ID", por ejemplo.

En segundo lugar, para obtener las relaciones 1: N correctas necesita hacer un paso manual adicional. Por ejemplo, hice una combinación de participantes de dos mesas y sus números de teléfono. Entonces tuve que hacer esto:

private List<Participant> CollapseResultSet(List<Participant> rawdataset)
{
    List<Participant> ret = new List<Participant>();
    if (!rawdataset.Any())
    {
        return ret;
    }
    else
    {
        List<string> partIds = rawdataset.Select(p => p.ID).Distinct().ToList();
        foreach (string pId in partIds)
        {
            Participant tmp = rawdataset.Where(p => p.ID == pId).FirstOrDefault();
            tmp.PhoneNumbers = rawdataset.Where(p => p.ID == pId).Select(n => n.PhoneNumbers[0]).ToList();
            ret.Add(tmp);
        }
        return ret;
    }
}

Espero que ayude.



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é