2011-12-21 9 views
12

Estoy tratando de reemplazar un desagradable SQL hit LINQ 2 con algunas consultas aptas para mejorar el rendimiento. Al hacerlo, tengo que tejer varios objetos diferentes para crear el objeto grande requerido para contener toda la información que necesito para la información de ASN.dapper PropInfo Setter para EntitySet heredado de la referencia de clase abstracta es nulo

El problema actual que estoy teniendo es un pedido de clase abstracta, esta clase es implementada por dos clases separadas AutionOrder y MerchantOrder usando una propiedad discriminator.

Como no puedo usar dapper para crear un objeto que sea una clase abstracta, en su lugar estoy usando una de las clases públicas. sin embargo, cuando se trata de construir el objeto que está fallando dentro de GetSettableProps está encontrando el DeclaringType adecuado, pero el método GetProperty está devolviendo nulo cuando está buscando una propiedad que es internal o es EntitySet. Intenté hackearlo utilizando t.BaseType.GetProperty y p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true) sin éxito.

objetos ficticios:

Solicitar

OrderID, nombre, dirección, rowversion (interna), los envíos (EntitySet), OrderDetails (EntitySet), cliente (EntityRef)

Envío

ShipmentID, Ord ERID, Trackingnumber

OrderDetails

OrderDetailID, IdPedido, producto, cantidad, precio

cliente

CustomerID, nombre,

Para este hit de SQL particular, estoy tratando de obtener algunas de las asignaciones de relación 1 a 1 que necesito.

SELECCIONAR o. * De ordenes como o deja unirse a Clientes como c en o.ID de cliente = c.ID de cliente donde o.ID de codificador en (1,2,3);

Esto es lo que estoy utilizando para utilizar pulcro y dejar que haga su magia:

using (var connection = new SqlConnection(_ConnectionString)) 
{ 
    connection.Open(); 
    results = connection.Query<MerchantOrder, MerchantCustomer, MerchantOrder>(sql.ToString(), 
     (o, c) => { o.Customer = c; return o; }, 
     splitOn: "CustomerID"); 
} 

Si cambio el fin de ser una clase pública este problema desaparece, sin embargo, pero esto no es un efecto deseado efecto secundario. Está fallando al intentar establecer el propInfo para RowVersion - cambiando esto a púbico en lugar de interno resuelto este problema - aunque no deseado. Pero luego falla cuando intenta crear los objetos Envíos para el pedido. De nuevo, nada de esto es un problema cuando Order es una clase pública.

También realizo consultas separadas para incorporar relaciones de muchos a uno, tales como envíos a pedidos y detalles de pedidos a pedidos, y la normalización de los resultados en un objeto de pedido adecuado. MerchantOrder es prácticamente una clase vacía sin una lógica especial. La diferencia de discriminación aquí es cómo terminamos encontrando el CustomerID que se abstrae antes de que el SQL real golpee de todos modos.

También estoy utilizando la última versión de dapper a partir del 20/12/2011.

Me gusta mucho, pero este problema me está haciendo ascender la cabeza, ¡gracias por la ayuda!

+0

se puede añadir una prueba en su defecto por lo que puedo solucionar este problema? solo envíe un parche con él –

+0

He añadido una prueba de falla @ https://code.google.com/r/johnzaborow-fail-test/ Estaba teniendo muchos problemas presionando automáticamente mis cambios, así que lo hice uno por uno . avísame si algo necesita ser cambiado. ¡Gracias! – John

+0

arreglado ahora, gracias! –

Respuesta

7

Esto fue un error, que ahora se fija en el maletero:

public class AbstractInheritance 
    { 
     public abstract class Order 
     { 
      internal int Internal { get; set; } 
      protected int Protected { get; set; } 
      public int Public { get; set; } 

      public int ProtectedVal { get { return Protected; } } 
     } 

     public class ConcreteOrder : Order 
     { 
      public int Concrete { get; set; } 
     } 
    } 

    // http://stackoverflow.com/q/8593871 
    public void TestAbstractInheritance() 
    { 
     var order = connection.Query<AbstractInheritance.ConcreteOrder>("select 1 Internal,2 Protected,3 [Public],4 Concrete").First(); 

     order.Internal.IsEqualTo(1); 
     order.ProtectedVal.IsEqualTo(2); 
     order.Public.IsEqualTo(3); 
     order.Concrete.IsEqualTo(4); 

    } 

Una nota es que, por diseño, no nos fijamos campos privados o propiedades de las clases base. El comportamiento puede ser mágico y no consistente.

Ej:

class A { private int a {get; set;} } 
class B : A { private int a {get; set;} } 
class C: B {} 

// What should "select 1 a" do? Set it on A? Set it on B? Set it on Both? Set it on neither? 

Fuimos con "la puso en ni"

+0

¡Muchas gracias por la solución! ¡Esto me hizo rascar mi cabeza por un tiempo! ¡El mejor regalo de cumpleaños que recibí este año! – John

+0

sin preocupaciones, ¡me alegro de que funcionó! –

0

Creo que no es posible (debido a la clase abstracta) sin modificar su código.

Tuve un problema similar y terminé creando un nuevo objeto privado para el ensamblado donde tengo mis repositorios derivados de la clase base abstracta.

Esta clase es no abstracta y solo visible para la clase de repositorio que almacena los datos, esta clase tenía todos los métodos necesarios para la tabla actual.

Cuestiones relacionadas