Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Advanced data access with Dapper

23 views

Published on

Session delivered at PrDC Winnipeg 2018.
Advanced .NET data access techniques using the Dapper Micro ORM

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Advanced data access with Dapper

  1. 1. Advanced Data Access with Dapper @Dave_Paquette Microsoft MVP (ASP.NET/IIS) contactme@davepaquette.com http://www.davepaquette.com
  2. 2. Data Access How did we get here? Why is this so hard? public class Foo { //…some properties } SQL Server
  3. 3. Data Access in .NET • In the beginning there was System.Data • IDbConnection • IDbCommand • IDataReader • IDbTransaction
  4. 4. Sytem.Data - Reading Records var results = new List<Employee>(); using (SqlConnection connection = new SqlConnection(Settings.ConnectionString)) { SqlCommand command = new SqlCommand(“SELECT * FROM Employees”, connection); connection.Open(); IDataReader reader = command.ExecuteReader(); while (reader.Read()) { results.Add(ReadSingleRow(reader)); } reader.Close(); } return results;
  5. 5. The ORMs will save us • Hide details of database • Generate SQL based on object model and configuration • ChangeTracking • Complex mapping strategies • Many-to-many relationships • Inheritance
  6. 6. Popular ORMs •Entity Framework •nHibernate? •Linq2Sql?
  7. 7. ORM Pain Points • Black box code generation –What is going on? • Performance Problems • Eager Loading vs Lazy Loading • Complex Inheritance Chains • Dealing with disconnected entities (in a web context)
  8. 8. The Micro-ORMs will save us! • Query --> Objects • Usually focused on speed • Light on features
  9. 9. Popular Micro-ORMs • Dapper • PetaPOCO • Massive • Simple.Data
  10. 10. Dapper • Used in production at Stack Exchange • Super fast and easy to use
  11. 11. Performance of SELECT mapping over 500 iterations - POCO serialization Method Duration Hand coded (using a SqlDataReader) 47ms Dapper ExecuteMapperQuery 49ms ServiceStack.OrmLite (QueryById) 50ms PetaPoco 52ms BLToolkit 80ms SubSonic CodingHorror 107ms NHibernate SQL 104ms Linq 2 SQL ExecuteQuery 181ms Entity framework ExecuteStoreQuery 631ms https://github.com/StackExchange/dapper-dot-net#performance-of-select-mapping-over-500-iterations---dynamic-serialization
  12. 12. How can it be that fast? • Dapper dynamically writes code for you • Emits IL code for tasks like loading a data reader into an object • https://github.com/StackExchange/Dapper/blo b/master/Dapper/SqlMapper.cs#L3078
  13. 13. Dapper works on Database Connections A set of extension methods on IDbConnection Aircraft aircraft; using (var connection = new SqlConnection(_connectionString)) { await connection.OpenAsync(); //Optional var query = "SELECT * FROM Aircraft WHERE Id = @Id"; Aircraft aircraft = await connection.QuerySingleAsync<Aircraft>(query, new {Id = id}); }
  14. 14. Querying Simple Objects Aircraft aircraft = await connection.QuerySingleAsync<Aircraft>(query, new {Id = id}); IEnumerable<Aircraft> aircraft = await connection.QueryAsync<Aircraft>(query);
  15. 15. Loading Related Objects – Multi-Mapping • Write a single query that returns all the data in a single row scheduledFlights = await connection.QueryAsync<ScheduledFlight, Airport, ScheduledFlight>(query, (flight, airport) => { flight.Airport = airport; return flight; }, new{FromCode = from} );
  16. 16. Multi-Mapping Caveats • Data duplication • Query returns a bloated data set • Multiple instances of an object that represent the same thing • This is totally fine forOne-to-One relationships • No duplication here
  17. 17. Loading Related Objects – Multiple Queries • Get data using multiple queries and wire them up yourself • Still executed in a single command that returns multiple results sets using (var multi = await connection.QueryMultipleAsync(query, new{FromCode = from} )) { scheduledFlights = multi.Read<ScheduledFlight>(); var airports = multi.Read<Airport>().ToDictionary(a => a.Id); foreach(var flight in scheduledFlights) { flight.Airport = airports[flight.AirportId]; } }
  18. 18. Multi-Mapping vs Multiple Queries 100 ScheduledFlight Records 1,000 ScheduledFlight Records Method Mean MultiMapping 926.5 us MultipleResultSets 705.9 us Method Mean MultiMapping 5.098 ms MultipleResultSets 2.809 ms
  19. 19. Loading More Complex Object Graphs
  20. 20. Loading More Complex Object Graphs
  21. 21. Paging through large collections • Use an OFFSET FETCH query • Include a total count in the result SELECT * FROM Flight f INNER JOIN ScheduledFlight sf ON f.ScheduledFlightId = sf.Id ORDER BY Day, FlightNumber OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY SELECT COUNT(*) FROM Flight f INNER JOIN ScheduledFlight sf ON f.ScheduledFlightId = sf.Id
  22. 22. Insert / Update / Delete • Use the ExecuteAsync method • Built-in support for batch inserts await connection.ExecuteAsync( @"INSERT INTO Flight(ScheduledFlightId, Day, ScheduledDeparture, ScheduledArrival) VALUES(@ScheduledFlightId, @Day, @ScheduledDeparture, @ScheduledArrival)", flights);
  23. 23. Buffering •Working with really large result sets? • Consider setting buffering=false for queries
  24. 24. Dapper Contrib • Generates SQL for simple CRUD operations
  25. 25. Questions? Check out my blog posts http://bit.ly/dapperseries
  26. 26. www.davepaquette.com westerndevs.com aspnetmonsters.com Blog(s) Twitter @Dave_Paquette Email contactme@davepaquette.com Thanks!

×