Sto provando a sostituire un brutto hit LINQ 2 SQL con alcune query dapper per migliorare performanace. In tal modo devo tessere un mucchio di oggetti diversi insieme per creare il grande oggetto necessario per contenere tutte le informazioni di cui ho bisogno per le informazioni ASN.
Il problema corrente che sto avendo è con una classe astratta Orders, questa classe è implementata da due classi separate AutionOrder e MerchantOrder che utilizzano una proprietà discriminator.
Dal momento che non posso usare dapper per creare un oggetto che è una classe astratta, sto usando invece una delle classi pubbliche. tuttavia quando si va a costruire l'oggetto sta venendo a mancare all'interno di GetSettableProps
sta trovando la giusta DeclaringType
ma il GetProperty
metodo sta tornando null quando si è alla ricerca di una proprietà che è internal
o è un EntitySet
. Ho provato a modificarlo usando t.BaseType.GetProperty
e p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true)
senza successo.
oggetti fittizi:
Ordine
ID ordine, Nome, Indirizzo, RowVersion (interno), Spedizioni (EntitySet), OrderDetails (EntitySet), Customer (EntityRef)
Spedizione
Spedizione ID, OrderID, TrackingNumber
OrderDetails
OrderDetailID, OrderID, Product, QTY, Price
Cliente
CustomerID, nome,
Per questo particolare attacco SQL sto provando ad afferrare alcuni dei mapping delle relazioni 1 a 1 di cui ho bisogno.
SELEZIONA o. * Da Ordini come o lasciati Iscriviti a clienti come c su o.CustomerID = c.CustomerID dove o.OrderID in (1,2,3);
Questo è quello che sto usando per usare dapper e lasciarlo fare è magico:
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");
}
Se cambio Ordine in una classe pubblica, questo problema va via, ma questo non è un effetto collaterale desiderato. Sta fallendo quando si tenta di impostare il propInfo per RowVersion - cambiando questo in public invece di internal risolto questo problema - sebbene non desiderato. Ma poi fallisce quando sta cercando di creare gli oggetti Spedizioni per Ordine. Di nuovo, niente di questo è un problema quando Order è una classe pubblica.
Inoltre sto facendo query separate per inserire relazioni da molti a uno come Spedizioni verso ordini e OrderDetails su ordini e normalizzando i risultati in un oggetto ordine appropriato. MerchantOrder è praticamente una classe vuota senza una vera e propria logica speciale. Il diverso discriminante qui è solo come finiamo per trovare il CustomerID che viene sottratto via prima del vero hit SQL comunque.
Inoltre sto usando l'ultima versione di dapper del 20/12/2011.
Mi piace molto dapper, ma questo problema mi sta facendo capire la mia testa - quindi grazie per l'aiuto!
Questo era un bug, che ora è stato risolto nel trunk:
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 a margine è che, per impostazione, non impostiamo campi privati o proprietà nelle classi base. Il comportamento può essere magico e non coerente.
Per esempio:
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?
Siamo andati con "non impostarlo su nessuno"
Penso che non sia possibile (a causa della classe astratta) senza modificare il tuo codice.
Ho avuto un problema simile e ho finito per creare un nuovo oggetto privato nell'assembly dove ho i miei repository derivati dalla classe base astratta.
Questa classe non è astratta e visibile solo per la classe di repository che memorizza i dati, questa classe ha tutti i metodi richiesti per la tabella effettiva.