¿Cómo crear una consulta de mapeo múltiple en Dapper con mapeo profundo de tres niveles?

c# dapper

Pregunta

Intento hacer una consulta que mapee correctamente lo siguiente:

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int BId {get; set; }
    public List<B> { get; set; }
}

public class B
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CId { get; set; }
    public int DId { get; set; }
    public C C { get; set; }
    public D D { get; set; }
}

public class C
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class D
{
    public int Id { get; set; }
    public string Name { get; set; }
}

¿Cómo escribo una consulta que mapea correctamente la entidad A con una lista de la entidad B con C y D llenos?

Respuesta aceptada

Desea hacer dos consultas aquí, para capturar la naturaleza uno a muchos de B en A. Además, sus B probablemente vayan a necesitar una referencia a A en la consulta.

var query1 = conn.Query<A>(select * from dbo.A)

var query2 = conn.Query<B,C,D,B>("select * from dbo.B...join C...join 

D",(b,c,d)=>{



     b.C = c;
        b.D = d;

return b;

        }

Ahora deberás conectarlos juntos. Yo uso linq joins y extensiones para automatizar un montón, pero la esencia es, recorrer cada 'A' y encontrar las 'B' correspondientes de la consulta 2. Los diccionarios y las listas también pueden ser más rápidas que las cláusulas 'Where', así que puede escribir una extensión que optimice el ciclo a continuación.

foreach(var a in query1){
a.Bs = query2.Where(w=>w.AId.Equals(a.Id));
}

Tenga en cuenta que puede reducir los viajes a la base de datos utilizando QueryMultiple para devolver múltiples conjuntos de registros (si su base de datos lo admite).


Respuesta popular

Probablemente podrías lograr en un viaje de ida y vuelta a la base de datos usando Drapper (construido sobre Dapper).

Suponiendo que tiene un conjunto de consultas SQL que devuelven resultados múltiples:

select * from [TableA]; 
select * from [TableB]; 
select * from [TableC]; 
select * from [TableD]

... con cada resultado que tenga algún tipo de identificador / clave externa para los demás, probablemente puedas construir un repositorio como el siguiente:

public class Repository : IRepository
{
    // IDbCommander is a Drapper construct.
    private readonly IDbCommander _commander;

    public Repository(IDbCommander commander)
    {
        _commander = commander;
    }

    public IEnumerable<A> RetrieveAll()
    {
        // execute the multiple queries and 
        // pass control to a mapping function.
        return _commander.Query(Map.Results);
    }

    private static class Map
    {
        internal static Func<IEnumerable<A>,
                            IEnumerable<B>,
                            IEnumerable<C>,
                            IEnumerable<C>,
                            IEnumerable<A>> Results = (collectionA, collectionB, collectionC, collectionD) => 
        {
            // map C and D to B based on their Id's
            collectionB.C = collectionC.SingleOrDefault(c => c.Id == b.Id);
            collectionB.D = collectionD.SingleOrDefault(d => d.Id == b.Id);

            // now map B to A.
            collectionA.B = collectionB.Where(b => b.Id == a.Id).ToList();
            return collectionA;
        }
    }
}

Ejemplo escrito desde la memoria para que la sintaxis esté un poco descuidada pero obtienes la esencia.

Estoy de acuerdo con BlackjacetMack en que deberías tener algún tipo de paginación en los resultados (también soportado en Drapper).



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é