Comportamiento inesperado con una consulta de mapeo múltiple usando Dapper.net

asp.net c# dapper mapping

Pregunta

Acabo de empezar a buscar en Dapper.net y he estado experimentando con algunas consultas diferentes, una de las cuales está produciendo resultados extraños que no esperaba.

Tengo 2 tablas: Photos y categorías de PhotoCategories , de las cuales están relacionadas en CategoryID

Tabla de fotos

PhotoId (PK - int)  
CategoryId (FK - smallint)  
UserId (int)

PhotoCategories Table

CategoryId (PK - smallint)  
CategoryName (nvarchar(50))

Mis 2 clases:

public class Photo
{
    public int PhotoId { get; set; }
    public short CategoryId { get; set; }
    public int UserId { get; set; }
    public PhotoCategory PhotoCategory { get; set; }
}

public class PhotoCategory
{
    public short CategoryId { get; set; }
    public string CategoryName { get; set; }
{

Quiero usar el mapeo múltiple para devolver una instancia de Photo , con una instancia poblada de la PhotoCategory relacionada.

var sql = @"select p.*, c.* from Photos p inner 
            join PhotoCategories c 
            on p.CategoryID = c.CategoryID where p.PhotoID = @pid";

cn.Open();
var myPhoto = cn.Query<Photo, PhotoCategory, Photo>(sql, 
               (photo, photoCategory) => { photo.PhotoCategory = photoCategory; 
                                           return photo; }, 
               new { pid = photoID }, null, true, splitOn: "CategoryID").Single();

Cuando se ejecuta esto, no todas las propiedades se están llenando (a pesar de tener los mismos nombres entre la tabla DB y mis objetos).

Noté que si don't selecciono p. * Etc. en mi SQL , y en su lugar.

Declaro explícitamente los campos.

Quiero volver EXCLUDING p.CategoryId de la consulta, luego todo se llena (excepto obviamente la CategoryId contra el objeto Photo que he excluido de la instrucción select).

Pero esperaría poder incluir ese campo en la consulta y tenerlo, así como todos los demás campos consultados dentro del SQL , para que se llene.

Podría excluir la propiedad CategoryId de mi clase Photo y siempre usar Photo.PhotoCategory.CategoryId cuando necesite la ID.

Pero en algunos casos, es posible que no desee rellenar el objeto PhotoCategory cuando obtengo una instancia del objeto Photo.

¿Alguien sabe por qué está ocurriendo el comportamiento anterior? ¿Es esto normal para Dapper?

Respuesta aceptada

Acabo de comprometer una solución para esto:

    class Foo1 
    {
        public int Id;
        public int BarId { get; set; }
    }

    class Bar1
    {
        public int BarId;
        public string Name { get; set; }
    }

    public void TestMultiMapperIsNotConfusedWithUnorderedCols()
    {

        var result = connection.Query<Foo1,Bar1,
                      Tuple<Foo1,Bar1>>(
                         "select 1 as Id, 2 as BarId, 3 as BarId, 'a' as Name",
                         (f,b) => Tuple.Create(f,b), splitOn: "BarId")
                         .First();

        result.Item1.Id.IsEqualTo(1);
        result.Item1.BarId.IsEqualTo(2);
        result.Item2.BarId.IsEqualTo(3);
        result.Item2.Name.IsEqualTo("a");

    }

El multi-mapeador se confundía si había un campo en el first tipo, que también estaba en el second tipo ... Y ... se usaba como punto de división.

Para superar ahora, dapper permite que el campo Id aparezca en cualquier parte del primer tipo. Para ilustrar.

Digamos que tenemos:

classes: A{Id,FooId} B{FooId,Name}
splitOn: "FooId"
data: Id, FooId, FooId, Name

El antiguo método de división no tenía en cuenta el tipo subyacente real que estaba mapeando. Entonces ... mapeó Id => A y FooId, FooId, Name => B

El nuevo método es consciente de los puntales y los campos en A Cuando se encuentra FooId primera vez en la transmisión no inicia una división, ya que sabe que A tiene una propiedad llamada FooId que necesita ser asignada, la próxima vez que vea FooId se dividirá, lo que dará como resultado los resultados esperados.


Respuesta popular

Sé que esta pregunta es antigua, pero pensé que podría ahorrarle a alguien 2 minutos con la respuesta obvia a esto: simplemente alias una identificación de una mesa:

es decir:

SELECT
    user.Name, user.Email, user.AddressId As id, address.*
FROM 
    User user
    Join Address address
    ON user.AddressId = address.AddressId


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é