2011-05-14 23 views
16

Jugando con Dapper, estoy bastante satisfecho con los resultados hasta ahora, ¡intrigante!No se puede obtener el mapeo múltiple para trabajar en Dapper

Pero ahora, mi próximo escenario sería leer datos de dos tablas: una tabla Student y una tabla Address.

Student tabla tiene una clave principal de StudentID (INT IDENTITY), Address tiene un AddressID (INT IDENTITY). Student también tiene un FK llamado AddressID vinculándolo a la tabla Address.

Mi idea era crear dos clases, una para cada mesa, con las propiedades que me interesan. Además, puse un PrimaryAddress propiedad de tipo Address en mi clase Student en C#.

Luego trató de recuperar tanto los datos de los estudiantes y de direcciones en una sola consulta - que imitan la muestra que se le da en la Github page:

var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; }); 
var post = data.First(); 

Aquí, un Post y una User se recuperan, y el titular de la publicación se establece para el usuario; el tipo devuelto es Post - ¿correcto?

Así que en mi código, definen dos parámetros al genérico método Query extensión - un Student como la primera que debe ser devuelto, y un Address como el segundo, que será almacenada en la instancia estudiante:

var student = _conn.Query<Student, Address> 
        ("SELECT s.*, a.* FROM dbo.Student s 
         INNER JOIN dbo.Address a ON s.AddressID = a.AddressID 
         WHERE s.StudentenID = @Id", 
        (stu, adr) => { stu.PrimaryAddress = adr; }, 
        new { Id = 4711 }); 

el problema es - me aparece un error en Visual Studio:

Utilizando el método genérico 'Dapper.SqlMapper.Query (System.Data.IDbConnection, cadena, System.Func, dinámico, System.Data.IDbTransaction, bool, string, int ?, System.Data.CommandType?)' Requiere 6 argumentos de tipo

Realmente no entiendo por qué Dapper insiste en usar esta sobrecarga con 6 argumentos tipo ...

+2

que tenían exactamente el mismo problema y me tomó un tiempo para averiguar por qué - como explica Sam! –

Respuesta

21

Eso sería porque cambié las API y olvidé actualizar la documentación, corrigí el error.

Asegúrese de echar un vistazo a Tests.cs para obtener una especificación actualizada.

En particular, la antigua API solía tomar en Action<T,U> para realizar la asignación, el problema era que se sentía arbitrario e inflexible. No se pudo controlar completamente el tipo de devolución. Las nuevas API toman en Func<T,U,V>. Para que pueda controlar el tipo que obtiene del mapeador y no necesita ser un tipo mapeado.

simplemente Amarré cierta flexibilidad adicional alrededor de mapeo múltiples, esta prueba debe dejar claro:

class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
} 

class Address 
{ 
    public int AddressId { get; set; } 
    public string Name { get; set; } 
    public int PersonId { get; set; } 
} 

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

public void TestFlexibleMultiMapping() 
{ 
    var sql = 
@"select 
1 as PersonId, 'bob' as Name, 
2 as AddressId, 'abc street' as Name, 1 as PersonId, 
3 as Id, 'fred' as Name 
"; 
    var personWithAddress = connection.Query<Person, Address, Extra, Tuple<Person, Address,Extra>> 
     (sql, (p,a,e) => Tuple.Create(p, a, e), splitOn: "AddressId,Id").First(); 

    personWithAddress.Item1.PersonId.IsEqualTo(1); 
    personWithAddress.Item1.Name.IsEqualTo("bob"); 
    personWithAddress.Item2.AddressId.IsEqualTo(2); 
    personWithAddress.Item2.Name.IsEqualTo("abc street"); 
    personWithAddress.Item2.PersonId.IsEqualTo(1); 
    personWithAddress.Item3.Id.IsEqualTo(3); 
    personWithAddress.Item3.Name.IsEqualTo("fred"); 

} 

tuberías Dapper todas las API de varios de mapeo a través de un único método, por lo que si algo falla que va a terminar en el 6 param uno.La otra pieza del rompecabezas fue que no permití algunas divisiones súper flexibles, que acabo de agregar.

Nota, la splitOn parámetro por defecto a Id, lo que significa que tendrá una columna llamada id o Id como el primer límite del objeto. Sin embargo, si necesita límites en varias claves principales que tienen diferentes nombres para decir un mapeo múltiple de "3 vías", ahora puede pasar una lista separada por comas.

Así que si tuviéramos que fijar el anterior, probablemente el siguiente funcionaría:

var student = _conn.Query<Student,Address,Student> 
       ("SELECT s.*, a.* FROM dbo.Student s 
        INNER JOIN dbo.Address a ON s.AddressID = a.AddressID 
        WHERE s.StudentenID = @Id", 
       (stu, adr) => { stu.PrimaryAddress = adr; return stu;}, 
       new { Id = 4711 }, splitOn: "AddressID").FirstOrDefault(); 
+0

Bien, gracias, pero ¿cómo puedo agregar algunos criterios como 'StudentId = @ Id' (y luego establecer' @ID = 4711') en esta consulta de asignación múltiple? –

+1

@marc_s editado que en ... –

+0

@marc_s tenga en cuenta que hay un montón de params opcionales para controlar cosas como tipo de comando, tiempo de espera de comando, etc. uno muy importante para aprender es "buffer" que te permite almacenar los resultados de manera que no tengas SqlReaders interviniendo el uno al otro –

Cuestiones relacionadas