Maggio 2016
Volume 31 Numero 5
Il presente articolo è stato tradotto automaticamente.
Punti dati - Dapper, Entity Framework e app ibride
Da Julie Lerman
Si sarà notato che scrivo molto su Entity Framework, il Microsoft relazionale Mapper ORM (Object) che è stato l'accesso di dati .NET principale API dal 2008. Sono disponibili altri ORM .NET, ma una determinata categoria, micro-ORM, diventa molto nota ottime prestazioni. Il prodotto ORM micro che ho sentito dire più indicata è Dapper. Cosa infine suscitato l'interesse abbastanza per alcuni tempo necessario per identificare il open è stata recentemente diversi sviluppatori reporting che create soluzioni ibride con Entity Framework e Dapper, consentendo di eseguire ogni ORM che cos'è ottimale in una singola applicazione.
Dopo la lettura di numerosi articoli e blog post, conversare con gli sviluppatori e giocare un po' con Dapper, si desidera condividere l'individuazione, soprattutto con coloro che, come me, probabilmente sentito parlare di Dapper, ma non è nota che cos'è o il funzionamento, o il motivo per cui gli utenti entusiasti. Tenere presente che sono in alcun modo un esperto. Invece informazioni sufficienti per soddisfare la curiosità per il momento e si spera stimolare l'interesse dimostrato in modo verranno esaminati ulteriormente.
Il motivo per cui Dapper?
Dapper presenta un'interessa cronologia, con generati da una risorsa che potrebbe essere estremamente familiare con: Marc Gravell e Sam Saffron creato Dapper quando si lavora in Overflow dello Stack, risoluzione dei problemi di prestazioni con la piattaforma. Overflow dello stack è un sito di traffico elevato seriamente che è destinato a motivi di prestazioni. In base alla pagina Exchange su Stack Overflow dello Stack si 5.7 miliardi di pagine negli 2015. Nel 2011, zafferano ha scritto un blog post ha sul lavoro e Gravell è stata completata, intitolato "Come I appreso per arrestare doversi e scrivere My proprio ORM" (bit.ly), che illustra i problemi di prestazioni dello Stack è stato visto contemporaneamente, derivanti dall'uso di LINQ to SQL. È quindi in dettaglio perché scrivendo un ORM personalizzata, Dapper, è stata la risposta per l'ottimizzazione di accesso ai dati in Overflow dello Stack. Cinque anni in un secondo momento, Dapper è ampiamente utilizzato e open source. Gravell e membro del team e Stack Nick Craver continuare a gestire attivamente il progetto in github.com/StackExchange/dapper-dot-net.
Dapper in a Nutshell
Dapper è incentrata sulla consentendo agli sviluppatori di esercitarsi con le proprie competenze SQL per creare query e comandi, come si pensa che debba essere. È più simile a "metallo" a una ORM standard, sblocco lo sforzo di interpretare le query, ad esempio LINQ a Entity Framework in SQL. Dapper hanno alcune interessanti funzionalità di trasformazione, ad esempio la possibilità di espandere un elenco passato a una clausola in cui IN. Ma nella maggior parte, SQL inviate a Dapper è pronto per essere e ottengono le query al database molto più rapidamente. Se si è in SQL, è possibile che si sta scrivendo la maggior parte dei comandi efficiente possibile. È necessario creare un tipo di IDbConnection, ad esempio un oggetto SqlConnection con una stringa di connessione noto, per eseguire le query. Quindi, con l'API Dapper possono eseguire le query per l'utente e, fornito lo schema dei risultati della query può essere abbinato le proprietà del tipo di destinazione, creare un'istanza automaticamente e popolati con i risultati della query. Esiste un altro vantaggio di prestazione da notare qui: Dapper vengono memorizzati nella cache in modo efficace il mapping che è stato molto veloce deserializzazione delle query successive. La classe verrà popolo, DapperDesigner (illustrato nella Figura 1), viene definito per la gestione di finestre di progettazione che effettuano molto dapper clothing.
Figura 1 DapperDesigner classe
public class DapperDesigner
{
public DapperDesigner() {
Products = new List<Product>();
Clients = new List<Client>();
}
public int Id { get; set; }
public string LabelName { get; set; }
public string Founder { get; set; }
public Dapperness Dapperness { get; set; }
public List<Client> Clients { get; set; }
public List<Product> Products { get; set; }
public ContactInfo ContactInfo { get; set; }
}
Il progetto in cui in esecuzione di query contiene un riferimento a Dapper, che è possibile recuperare tramite NuGet (install-package dapper). Di seguito è una chiamata di esempio da Dapper per eseguire una query per tutte le righe nella tabella DapperDesigners:
var designers = sqlConn.Query<DapperDesigner>("select * from DapperDesigners");
Si noti che per i listati di codice in questo articolo, ho utilizzato select * anziché proiezione di colonne per le query in modo esplicito quando si desidero che tutte le colonne da una tabella. sqlConn è un oggetto SqlConnection esistente che è stata già creata un'istanza, unitamente alla stringa di connessione, ma non sono state aperte.
Il metodo di Query è un metodo di estensione fornito da Dapper. Quando viene eseguita questa riga, Dapper apre la connessione, crea un DbCommand, esegue la query esattamente come è stato scritto, crea un'istanza di un oggetto DapperDesigner per ogni riga nei risultati e li inserisce i valori dai risultati della query le proprietà degli oggetti. Dapper può corrispondere i valori dei risultati con le proprietà mediante alcuni modelli, anche se i nomi delle proprietà non corrispondono ai nomi di colonna e anche se le proprietà non sono nello stesso ordine delle colonne corrispondenti. Impossibile leggere menti, tuttavia, in modo non previsto di scoprire che implicano i mapping in cui gli ordini o i nomi delle colonne e delle proprietà non sono sincronizzati, ad esempio, i valori stringa diversi. Provo alcuni esperimenti dispari su di essa per vedere come risponderà e sono disponibili anche le impostazioni globali che controllano la modalità Dapper in grado di dedurre i mapping.
Query relazionali e dapper
Il tipo DapperDesigner presenta un numero di relazioni. Esiste un uno-a-molti (prodotti), uno a uno (ContactInfo) e molti-a-molti (client). Ho provato a eseguire query su tali relazioni e Dapper in grado di gestire le relazioni. Senz'altro non è facile come esprimere una query LINQ to Entity Framework con un metodo di inclusione o anche una proiezione. Delle competenze personali TSQL viene eseguito il push al limite, tuttavia, poiché Entity Framework ha mi ha consentito di acquisire in modo lazy negli ultimi anni.
Di seguito è riportato un esempio di una query sulla relazione uno-a-molti tramite SQL utilizzo destra nel database:
var sql = @"select * from DapperDesigners D
JOIN Products P
ON P.DapperDesignerId = D.Id";
var designers= conn.Query<DapperDesigner, Product,DapperDesigner>
(sql,(designer, product) => { designer.Products.Add(product);
return designer; });
Si noti che il metodo di Query è necessario specificare entrambi i tipi che devono essere costruiti, nonché indicare il tipo da restituire, espressa come parametro di tipo finale (DapperDesigner). Usare un'espressione lambda su più righe per costruire prima dei grafici, aggiungere i prodotti pertinenti agli oggetti della finestra di progettazione padre, quindi restituire ogni finestra di progettazione per l'interfaccia IEnumerable il metodo di Query restituisce.
Lo svantaggio di questa operazione con il miglior tentativo SQL è che i risultati vengono resi bidimensionali, come lo sarebbero con il metodo includono Entity Framework. Otterrà una riga per ogni prodotto con le finestre di progettazione duplicati. Dapper è un metodo MultiQuery che può restituire più gruppi di risultati. In combinazione con GridReader del Dapper, le prestazioni delle query saranno senz'altro oscurare include Entity Framework.
Più difficile da codice, più veloce da eseguire
Espressione SQL e la compilazione di oggetti correlati sono attività che ho consentire EF gestire in background, pertanto si tratta indubbiamente più complessa al codice. Ma se si lavora con grandi quantità di dati e le prestazioni di runtime sono importante, può essere sicuramente la pena. Il database di esempio contiene circa 30.000 finestre di progettazione. Solo alcune di esse sono prodotti. Ho fatto alcune prove comparative semplice in cui sono accertato che stavo confronto mele di mele. Prima di esaminare i risultati del test, esistono alcuni aspetti importanti da comprendere come ho fatto tali misurazioni.
Tenere presente che, per impostazione predefinita, Entity Framework è progettato per rilevare gli oggetti che sono riportati i risultati delle query. Ciò significa la creazione di oggetti di rilevamento aggiuntive, che richiede qualche sforzo e richiede inoltre di interagire con gli oggetti di rilevamento. Dapper, al contrario, solo esegue il dump dei risultati in memoria. È quindi importante per modifica di Entity Framework di eseguire il ciclo di rilevamento quando si esegue un confronto delle prestazioni. Faccio definendo tutte le query Entity Framework con il metodo AsNoTracking. Inoltre, quando si confrontano le prestazioni, è necessario applicare un numero di modelli di benchmark standard, ad esempio riscaldamento di database, ripetere la query più volte e generazione di volte più veloce e più lente. È possibile visualizzare i dettagli di come è stato creato il test di benchmark nel download di esempio. Ancora, considerare queste come test di benchmark "lightweight", per fornire un'idea delle differenze. Per i benchmark gravi, è necessario eseguire l'iterazione di molte altre volte a mio 25 (avvio 500) e al fattore di prestazioni del sistema in cui in esecuzione. Questi test vengono eseguiti in un computer portatile con un'istanza di LocalDB di SQL Server, pertanto i risultati sono utili solo per i migliori risultati del confronto.
I tempi che si tiene traccia per i miei test sono per l'esecuzione della query e i risultati di compilazione. Creazione di connessioni o DbContext non conteggiati. Oggetto DbContext viene riutilizzato in modo il tempo di Entity Framework compilare il modello in memoria non viene inoltre presa in considerazione, come questa situazione si verifica solo una volta per ogni istanza di applicazione, non per ogni query.
Figura 2 viene illustrato il "seleziona *" verifica per Dapper e LINQ EF query in modo da visualizzare il costrutto di base del mio modello di test. Si noti che all'esterno del tempo effettivo di raccolta, è la raccolta di volta per ogni iterazione in un elenco (denominato "ore") per un'ulteriore analisi.
Figura 2 test per confrontare Entity Framework e Dapper quando l'esecuzione di query DapperDesigners tutti
[TestMethod,TestCategory("EF"),TestCategory("EF,NoTrack")]
public void GetAllDesignersAsNoTracking() {
List<long> times = new List<long>();
for (int i = 0; i < 25; i++) {
using (var context = new DapperDesignerContext()) {
_sw.Reset();
_sw.Start();
var designers = context.Designers.AsNoTracking().ToList();
_sw.Stop();
times.Add(_sw.ElapsedMilliseconds);
_trackedObjects = context.ChangeTracker.Entries().Count();
}
}
var analyzer = new TimeAnalyzer(times);
Assert.IsTrue(true);
}
[TestMethod,TestCategory("Dapper")
public void GetAllDesigners() {
List<long> times = new List<long>();
for (int i = 0; i < 25; i++) {
using (var conn = Utils.CreateOpenConnection()) {
_sw.Reset();
_sw.Start();
var designers = conn.Query<DapperDesigner>("select * from DapperDesigners");
_sw.Stop();
times.Add(_sw.ElapsedMilliseconds);
_retrievedObjects = designers.Count();
}
}
var analyzer = new TimeAnalyzer(times);
Assert.IsTrue(true);
}
C'è un altro punto da eseguire sul confronto tra "mele di mele". Dapper accetta in SQL non elaborata. Per impostazione predefinita, le query Entity Framework sono espressi con LINQ to Entity Framework e devono passare attraverso uno sforzo per compilare il codice SQL per l'utente. Una volta che SQL viene compilato, anche SQL che si basa su parametri, viene memorizzato nella memoria dell'applicazione in modo da ridurre gli oneri sulla ripetizione. Inoltre, Entity Framework ha la possibilità di eseguire query tramite SQL non elaborata, pertanto ho adottato entrambi gli approcci in considerazione. Figura 3 sono elencati i risultati di comparate dei quattro set di test. Il download contiene anche altri test.
Figura 3 tempo medio in millisecondi per eseguire una Query e popolare un oggetto basato su 25 iterazioni, eliminando il più veloce e più lente
* AsNoTracking query | Relazione | LINQ a Entity Framework * | Entity Framework non elaborati SQL * | Dapper SQL non elaborata |
Tutte le finestre di progettazione (K 30 righe) | – | 96 | 98 | 77 |
Tutte le finestre di progettazione con i prodotti (K 30 righe) | 1 : * | 251 | 107 | 91 |
Tutte le finestre di progettazione con i client (K 30 righe) | * : * | 255 | 106 | 63 |
Tutte le finestre di progettazione con il contatto (K 30 righe) | 1 : 1 | 322 | 122 | 116 |
Negli scenari nel Figura 3, è facile creare un caso di utilizzo di Dapper su LINQ to Entities. Ma le differenze tra le query SQL non elaborate ristretta possono non sempre giustificare la commutazione a Dapper per attività specifiche in un sistema in cui in caso contrario si utilizza Entity Framework. Naturalmente, le proprie esigenze saranno diverse e potrebbero influire sul grado di variazione tra le query Entity Framework e Dapper. Tuttavia, in un sistema di traffico elevato, ad esempio l'Overflow dello Stack, anche i pochi millisecondi salvate per ogni query possono essere fondamentale.
Dapper ed Entity Framework per altre esigenze di persistenza
Finora ho misurata query semplici in cui appena estratti nuovamente tutte le colonne da una tabella che corrisponde esattamente le proprietà dei tipi restituiti. Cosa accade se si sta proiezione di query in tipi? Fino a quando lo schema dei risultati corrisponde al tipo, Dapper nota alcuna differenza nella creazione degli oggetti. Entity Framework, tuttavia, è difficile se non sono allineate i risultati della proiezione con un tipo che fa parte del modello.
Il DapperDesignerContext dispone di un elemento DbSet per il tipo DapperDesigner. Dispongo di un altro tipo nel mio sistema chiamato MiniDesigner che contiene un subset di proprietà DapperDesigner:
public class MiniDesigner {
public int Id { get; set; }
public string Name { get; set; }
public string FoundedBy { get; set; }
}
MiniDesigner non fa parte del mio modello di dati Entity Framework, in modo DapperDesignerContext non ha alcuna conoscenza di questo tipo. È stato rilevato che l'esecuzione di query tutte le 30.000 righe e proiezione in 30.000 MiniDesigner gli oggetti del 25% più veloce con Dapper rispetto con Entity Framework utilizza SQL non elaborata. Nuovamente, si consiglia di eseguire il proprio per prendere decisioni per il proprio sistema di profilatura delle prestazioni.
Dapper consente inoltre il push dei dati nel database con i metodi che consentono di identificare quali proprietà devono essere utilizzate per i parametri specificati dal comando, se si utilizza un inserimento non elaborato o comando di aggiornamento o si sta eseguendo una stored procedure o funzione nel database. Non qualsiasi confronto delle prestazioni per queste attività.
Ibrida Dapper Plus EF nel mondo reale
Esistono moltissimi sistemi che usano Dapper per il 100% la persistenza dei dati. Ma si tenga presente che è stato suscitato l'interesse a causa di sviluppatori parlando soluzioni ibride. In alcuni casi, questi sono i sistemi che dispongono di Entity Framework e cercano di modificare aree particolare problema. In altri casi, i team sono scelto di utilizzare Dapper per tutte le query ed Entity Framework per Salva tutti.
In risposta alla mia richiesta di informazioni su Twitter, ricevuto commenti variabili.
@garypochron ha riferito il suo team è stato "spostamento in avanti con utilizzo Dapper in aree chiamate & utilizzo file di risorse per la gestione dell'organizzazione di SQL". Ero sorpreso nello scoprire che Simon Hughes (@s1monhughes), autore del popolari EF invertire POCO generatore, passa la direzione opposta, ovvero l'impostazione Dapper e l'utilizzo di Entity Framework per i problemi di difficili. Ha detto mi "Io uso Dapper laddove possibile. Se si tratta di un aggiornamento complesso utilizzare Entity Framework."
Ho notato anche un'ampia gamma di discussioni in cui l'approccio ibrido è dovuta separazione delle problematiche anziché il miglioramento delle prestazioni. I più comuni di questi sfruttare la dipendenza predefinito di ASP.NET Identity Entity Framework e quindi utilizzare Dapper per il resto di persistenza nella soluzione.
Utilizzare più direttamente il database ha altri vantaggi oltre alle prestazioni. Rob Sullivan (@datachomp) e Mike Campbell (@angrypets), entrambi esperti di SQL Server, piace Dapper. Rob indica che è possibile sfruttare le funzionalità di database che Entity Framework non fornisce l'accesso, ad esempio ricerca full-text. Nel lungo termine, tale caratteristica è, in effetti, sulle prestazioni.
D'altra parte, sono presenti operazioni da eseguire con Entity Framework che non è possibile eseguire con Dapper oltre il rilevamento delle modifiche. Un buon esempio è uno sfruttato quando si compila la soluzione creata per questo articolo, ovvero la possibilità di eseguire la migrazione del database come modifiche del modello con migrazioni Code First di Entity Framework.
Dapper non è complessa, tuttavia. @damiangray mi che dapper non è un'opzione per la sua soluzione perché deve essere in grado di restituire IQueryables da una parte del suo sistema ai dati di un altro, non l'effettivo. In questo argomento, l'esecuzione posticipata delle query, è stato portato nel repository GitHub di Dapper alla bit.ly/22CJzJl, se si desidera ottenere maggiori informazioni. Quando si progetta un sistema ibrido, tramite alcune caratteristiche di comando Query separazione (CQS) consente di definire modelli separati per particolari tipi di transazioni (operazione che sono un appassionato della) è un percorso valido. In questo modo, si stava tentando di compilare codice di accesso ai dati che è abbastanza normale per funzionare con Entity Framework e Dapper, che comporta spesso compromettere le prestazioni di ogni ORM. Come ho lavorato in questo articolo, Kurt Dowswell pubblicato un post chiamato "Dapper, Entity Framework e CQS" (bit.ly/1LEjYvA). Utile per me e utile per l'utente.
Per gli utenti per il futuro di CoreCLR e ASP.NET di base, Dapper è stato migliorato in modo da includere il supporto per questi elementi, nonché. È possibile trovare ulteriori informazioni in un thread nel repository GitHub di Dapper alla bit.ly/1T5m5Ko.
Pertanto, infine, ho esaminato Dapper. Cosa penso?
E le informazioni personali? Ho spiacenti, ma non la necessità di esaminare in precedenza Dapper e felice che infine ho fatto. Sempre ho consigliabile AsNoTracking o utilizzando viste o procedure nel database per risolvere i problemi di prestazioni. Questo non è mai riuscito me o client. Ma ora si dispone di un altro trucco la mia sleeve consigliare agli sviluppatori che desiderano stesso come concentrare anche prestazioni migliori con i sistemi che utilizzano Entity Framework. Non è un shoo-in, come si dice. Il mio consiglio è necessario esplorare Dapper, misurazione della differenza di prestazioni (su larga scala) e trovare un equilibrio tra prestazioni e semplicità di codifica. È consigliabile utilizzare ovvio di StackOverflow: esecuzione di query domande, commenti e le risposte, quindi restituire grafici di una domanda con i commenti e le risposte insieme alcuni metadati (modifiche) e informazioni sull'utente. Essi eseguire gli stessi tipi di query e mapping out della stessa forma dei risultati in modo continuativo. Dapper è progettato per sviluppatori con questo tipo di query ricorrenti, recupero più rapido ed efficiente ogni ora. Anche se non si dispone di un sistema con il numero incredibile di transazioni che è stato progettato per Dapper, è probabile trovare una soluzione ibrida offre è la soluzione ideale.
Julie Lerman è un Microsoft MVP, mentore e consulente .NET che risiede nel Vermont. È possibile trovare le sue presentazioni relative all'accesso ai dati e altri argomenti su .NET in occasioni di conferenze che si tengono in tutto il mondo. Anna blog all'indirizzo thedatafarm.com ed è autore di "Programming Entity Framework" nonché Code First e un'edizione di DbContext, tutto da o ' Reilly Media. Seguirla su Twitter: @julielerman e vedere i corsi proprio Pluralsight PS/juliel.me-video.
Grazie per i seguenti esperti tecnici Overflow dello Stack per la revisione dell'articolo: Nick Craver e Marc Gravell
Nick Craver (@Nick_Craver) è uno sviluppatore, tecnico l'affidabilità del sito e talvolta DBA per Overflow dello Stack. Si è specializzato in tutti i livelli, architettura di sistema, hardware del data center di ottimizzazione delle prestazioni e la gestione di molti progetti open source, ad esempio Opserver. Contattarlo all'indirizzo
Marc Gravell è uno sviluppatore presso l'Overflow dello Stack, con particolare attenzione alle librerie ad alte prestazioni e strumenti per .NET, soprattutto accesso ai dati, la serializzazione e API di rete, che hanno contribuito a una gamma di progetti open source in queste aree.