Micro-ORM Introduction - Don't overcomplicate
-
Upload
kiev-altnet -
Category
Spiritual
-
view
5.664 -
download
0
Transcript of Micro-ORM Introduction - Don't overcomplicate
![Page 1: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/1.jpg)
Don't overcomplicateIntroduction to Micro ORM
Ivan Korneliuk@korneliukhttp://korneliuk.blogspot.com/31337
Kiev ALT.NET
![Page 2: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/2.jpg)
What wrong with ORM?
• Inadequate abstraction
• Inefficiency
• Complexity
• Requires overcomplicated infrastructure around
![Page 3: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/3.jpg)
Micro ORM
• Massive by Rob Connery
• Simple.Data by Mark Rendle
• Peta Poco by Top Ten Software
• Dapper by Sam Saffron
![Page 4: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/4.jpg)
dapper-dot-netSimple SQL object mapper for ADO.NET
• Created by StackOverflow guys
• Single file
• Read oriented
• Ultra fast - performance is a key feature
• Pure SQL
![Page 5: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/5.jpg)
dapper-dot-netMain concepts
Enrich IDbCommand with extension methods for querying and executing sql commands.
Can map query results to list of POCOs or dynamics.
![Page 6: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/6.jpg)
dapper-dot-netQuerying POCOs
public class Dog { public int? Age { get; set; } public Guid Id { get; set; } public string Name { get; set; } public float? Weight { get; set; } public int IgnoredProperty { get { return 1; } } }
var guid = Guid.NewGuid(); var dog = connection.Query<Dog>( "select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
dog.Count().IsEqualTo(1);dog.First().Age.IsNull();dog.First().Id.IsEqualTo(guid);
![Page 7: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/7.jpg)
dapper-dot-netAdvanced features
List support - automatically parameterize query by passing IEnumerable
connection.Query<int>( @"select * from (select 1 as Id union select 2 union select 3) as X where Id in @Ids", new { Ids = new int[] { 1, 2, 3 });
select * from (select 1 as Id union select 2 union all select 3) as X where Id in (@Ids1, @Ids2, @Ids3) // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3
![Page 8: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/8.jpg)
dapper-dot-netAdvanced features
Multi mapping - maps single row to several objects
var sql = @"select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id";var data = connection.Query<Post, User, Post>( sql, (post, user) => { post.Owner = user; return post;});
var post = data.First();
post.Content.IsEqualTo("Sams Post1"); post.Id.IsEqualTo(1); post.Owner.Name.IsEqualTo("Sam"); post.Owner.Id.IsEqualTo(99);
![Page 9: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/9.jpg)
dapper-dot-netAdvanced features
Multiple results - processes multiple result grids with a single query.
var sql = @“ select * from Customers where CustomerId = @id select * from Orders where CustomerId = @id select * from Returns where CustomerId = @id";
using (var multi = conn.QueryMultiple(sql, new {id=Id})) { var customer = multi.Read<Customer>().Single(); var orders = multi.Read<Order>().ToList(); var returns = multi.Read<Return>().ToList(); ... }
![Page 10: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/10.jpg)
• Buffered and unbuffered readers (fetching results)
• Executing Stored Procedures
• Dapper.Contrib - Handling C(r)UD operationso Marking classes with attributeso Change tracking
• Queries caching
dapper-dot-netAdvanced features
![Page 11: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/11.jpg)
MassiveSingle file database lover
"I wanted to stay as close to the "metal" as I possibly could. This (to me) meant that I didn't want to worry about Types, Tracking Containers, Contexts and so on. What I did want to do is describe my table - and this is the only type I have (which, ironically, is a Dynamic type)"
Single file with less than 700 lines of code (including comments).
![Page 12: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/12.jpg)
MassiveInitializing table// Create a class that wraps a tablepublic class Products:DynamicModel { public Products():base("northwind", "products","productid") {}}
// or instantiate it inlinevar tbl = new DynamicModel( "northwind", tableName:"Products", primaryKeyField:"ProductID");
![Page 13: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/13.jpg)
MassiveQuerying
var table = new Products();var products = table.All( columns: "ProductName as Name", where: "WHERE categoryID=@0", args: 4);
var products = table.Find(CategoryID:4,columns:"ProductName")
// Running ad-hoc queries as needed:var result = tbl.Query("SELECT * FROM Categories");var result = tbl.Fetch("SELECT * FROM Categories");
// Pagingvar result = tbl.Paged(where: "UnitPrice > 20", currentPage:2, pageSize: 20);
![Page 14: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/14.jpg)
MassiveUpdating
var table = new Products();var poopy = new {ProductName = "Chicken Fingers"};table.Update(poopy, 12);
// Works for a form on a web pagetable.Update(poopy, Request.Form);
// Insertvar table = new Categories();var newID = table.Insert(new {CategoryName = "Buck Fify Stuff", Description = "Things I like"});
// Batch updatesvar table = new Products();var drinks = table.All("WHERE CategoryID = 8");// what we get back here is an IEnumerable<ExpandoObject>foreach(var item in drinks){ item.CategoryID = 12;}table.Save(drinks);
![Page 15: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/15.jpg)
Massive
public class Productions :DynamicModel { public Productions(): base("MyConnectionString","Productions","ID") {} public override void Validate(dynamic item) { ValidatesPresenceOf("Title"); ValidatesNumericalityOf(item.Price); ValidateIsCurrency(item.Price); if (item.Price <= 0) Errors.Add("Price can't be negative"); }}
public class Customers: DynamicModel { public Customers():base("MyConnectionString","Customers","ID") {}
//Add the person to Highrise CRM when they're added to the system... public override void Inserted(dynamic item) { //send them to Highrise var svc = new HighRiseApi(); svc.AddPerson(...); }}
Changes notification
Validation
![Page 16: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/16.jpg)
PetaPocoTiny ORM to use with non-dynamic POCO objects
• Inspired by Massive but works with strongly typed POCOs
• Also supports dynamic Expandos
• T4 template for generating classes from database schema
• Marking classes with attributes
• The query language is SQL
• Helper methods for Insert/Delete/Update/Save and IsNew
• Hooks for logging exceptions, installing value converters and mapping columns to properties without attributes
• Works even if you stuck with .NET 3.5
![Page 17: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/17.jpg)
PetaPoco
Code samples
![Page 18: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/18.jpg)
Simple.Dataan ORM without O, the R or the M
"A lightweight, dynamic data access component for .NET"
![Page 19: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/19.jpg)
Simple.Data
• Microsoft.Data done right
• Really simple
• Protects from SQL injection
• Convention based and LINQ like syntax
• Master-detail relations without SELECT N+1
• Easy testing with mock database
![Page 20: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/20.jpg)
Simple.DataSyntax overview
dynamic db = Database.Open();User user = db.Users.FindByUserName("bob"); // Method name formuser = db.Users.FindBy(UserName: "bob"); // Named parameter form
@p0 = 'bob'SELECT * FROM Users WHERE UserName = @p0
IEnumerable<dynamic> customers = db.Customers .FindAll(db.Customers.CustomerName == "Arthur") .OrderByCustomerName() .Distinct();
@p1 = 'Arthur'select distinct dbo.customers.customerid, dbo.customers.customer_namefrom [dbo].[customers] where [dbo].[customers].[customer_name] = @p1 order by [customer_name]
FindAllBy
FindBy
![Page 21: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/21.jpg)
Simple.DataSyntax overview
var q = db.Employees.Query() .Join(db.Department, Id: db.Employees.DepartmentId) .Select(db.Employees.Name, db.Department.Name.As("Department"));
var q = db.Employees .Find(db.Employees.DepartmentId == db.Department.Id) .Select(db.Employees.Name, db.Department.Name.As("Department"));
select [dbo].[employee].[name], [dbo].[department].[name] as [Department] from [dbo].[employee]join [dbo].[department] on ([dbo].[department].[id] = [dbo].[employee].[departmentid])
Explicit join
Natural join (dynamic form)
![Page 22: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/22.jpg)
Simple.DataSyntax overview - Insert
var user = db.Users.Insert(Name: "Steve", Age: 50);
@p0 = 'Steve'@p1 = 50insert into [dbo].[Users] ([Name],[Age]) values (@p0,@p1)
var user = new User { Name = "Steve", Age = 50 };db.Users.Insert(user);
By object
Named parameters
Generated SQL:
Insert, Update and Delete methods return a row or rowSet of data that has just been modified.
Insert and Update can be used in two forms, Named parameters and by object. The object can be a POCO or a dynamic.
![Page 23: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/23.jpg)
Simple.DataSyntax overview - Update
db.Users.UpdateById(Id: 1, Name: "Steve", Age: 50);
@p0 = 1, @p1 = 'Steve', @p2 = 50update [dbo].[Users] set [Name] = @p1, [Age] = @p2 where [dbo].[Users].[Id] = @p3
dynamic record = new SimpleRecord();record.Id = 1;record.Name = "Steve";record.Age = 50;
db.Users.UpdateById(record); // Method name formdb.Users.Update(record); // By Primary Key
By object (can be POCO or dynamic)
Named parameters
Generated SQL:
![Page 24: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/24.jpg)
Simple.DataSyntax overview - UpdateAll
db.Users.UpdateAll(Name: "Steve");
@p0 = 'Steve'update [dbo].[Users] set [Name] = @p
Named parameters
db.Users.UpdateAll(Name: "Steve", Condition: db.Users.Age > 30);
db.Users.UpdateAll(db.Users.Age > 30, Name: "Steve");
With expression
@p0 = 'Steve'@p1 = 30update [dbo].[Users] set [Name] = @p0 where [dbo].[Users].[Age] > @p1
![Page 25: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/25.jpg)
Simple.DataSyntax overview - Delete
db.Users.Delete(Id: 1);
Named parameters
db.Users.DeleteById(Id: 1);
db.Users.DeleteAll(db.Users.Age > 42 && db.Users.Name.Like("J%"));
Method name form
db.Users.DeleteAll();
With expression
With no Where clause
![Page 26: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/26.jpg)
Simple.DataPersonal experience
Used in two production systems.
First one is CQRS based and Simple.Data is used to actualize “Read Model” there.
Within the second one, Simple.Data is used to store normalized data which we receive from third party in XML form.
In both systems Simple.Data is used for integration tests.
It just amazing how simpler design can be when you don’t need data classes just to map them to database tables.
![Page 27: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/27.jpg)
Simple.Data
Real code examples
![Page 28: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/28.jpg)
TL;DRWhat I liked in Micro ORMs
Usually leads to better performance. Though, that was not a key feature for me.
Write less, do more – instead of writing infrastructural code (Session management, Repositories, Specifications, Mappings etc.) you concentrated on getting things done…. things which business needs, not technical issues dictated by our infrastructure.
With less features in Micro ORMs you are forced to design things simpler – simpler object hierarchies, simpler database schema. And you are forced to apply good patterns. Separating Reads and Writes is a good example.
That all leads to a better design.
![Page 29: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/29.jpg)
ReferencesGeneral•“ORM is an anti-pattern” article – http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern •Micro ORM Samples – https://github.com/ijrussell/MicroORM
•InfoQ. Micro ORMs with Sam Saffron and Rob Conery – http://www.infoq.com/articles/ORM-Saffron-Conery•Hanselminutes Podcast 262 - The Rise of the Micro-ORM with Sam Saffron and Rob Conery http://www.hanselman.com/blog/HanselminutesPodcast262TheRiseOfTheMicroORMWithSamSaffronAndRobConery.aspx
Dapper-dot-net•Home – http://code.google.com/p/dapper-dot-net/ (with performance comparison)•“How I learned to stop worrying and write my own ORM” –http://samsaffron.com/archive/2011/03/30/How+I+learned+to+stop+worrying+and+write+my+own+ORM•“A day in the life of a slow page at Stack Overflow” - http://samsaffron.com/archive/2011/05/02/A+day+in+the+life+of+a+slow+page+at+Stack+Overflow
Massive•Home – https://github.com/robconery/massive•Rob Conery blog - http://wekeroad.com/
![Page 30: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/30.jpg)
ReferencesPetaPoco•Source – https://github.com/toptensoftware/petapoco•Documentation – http://www.toptensoftware.com/petapoco/
Simple.Data•Source – https://github.com/markrendle/Simple.Data•Documentation – http://simplefx.org/simpledata/docs/•Mark Rendle blog - http://blog.markrendle.net/•HERDING CODE 106: MARK RENDLE ON SIMPLE.DATA (podcast) – http://herdingcode.com/?p=305•.Net Rocks! podcast “Mark Rendle Has Some Simple.Data” – http://www.dotnetrocks.com/default.aspx?showNum=683
![Page 31: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/31.jpg)
Follow Friday@marcgravell
@markrendle
@robconery
@samsaffron
@toptensoftware
![Page 32: Micro-ORM Introduction - Don't overcomplicate](https://reader035.fdocuments.in/reader035/viewer/2022062405/5560c83dd8b42a08088b4755/html5/thumbnails/32.jpg)