SlideShare a Scribd company logo
ORM OR NOT ORM?
THAT IS THE QUESTION
BEZPALYI KYRYLO, .NET DEVELOPER @ CIKLUM
ABOUT ME
• .Net developer @ Ciklum
• Microsoft Student Partner
• An avid programmer
BEFORE WE BEGIN
ALL NON-TRIVIAL ABSTRACTIONS,
TO SOME DEGREE, ARE LEAKY.
Joel Spolsky,
The Law of Leaky Abstractions
YOU SHOULD ALWAYS
UNDERSTAND AT LEAST ONE
LAYER BELOW WHAT YOU ARE
CODING.
Lee Campbell, author of IntroToRX.com
SMALL HISTORY
• ADO.NET
• Data Sets
• Strong-typed Data Sets
• NHibernate
• LINQ to SQL
• Entity Framework
• EF Code First
• EF Core
WHAT IS .NET WAY TODAY?
• .NET
• ASP.NET (WebApi/MVC)
• Sql Server
• Entity Framework
WHAT’S .NET DEVELOPERS THINK ABOUT EF?
• Too much configuration (Fluent API, attributes, navigation properties, keys,
relations, etc.)
• Leaking abstractions (LINQ)
• Object model does not fit business model
• Things become complicated very fast
Кирилл Безпалый, .NET Developer, Ciklum
PROBLEM OF ENTITY FRAMEWORK
• Performance
• Parameter Sniffing
• Lazy Load
• Data Modification
• Some crazy stuff
Кирилл Безпалый, .NET Developer, Ciklum
HIDDEN POTENTIAN IQUERYABLE
• Do you know difference between IEnumerable and IQueryable. Lot of tutorials
don`t show full power of IQueryable showing only some simple examples.
• In practice: IQueryable has generic logic of query using Expression Trees data
structure and Provider that can transform this logic in query to some data source.
MORE ABOUT EXPRESSION TREE
• Expression tree it’s a tree of operations and their operands which
can be other operations
• Generally Expression tree is a serialized code
• Difference between IEnumerable and IQueryable:
• IEnumerable represent sequence of values, values processed by delegates
• IQueryable represent query collected with Expression Tree
• Expressions has deep integration in VS, so in some cases programmers don’t understand that their
lambda will be converted to some data structure instead of simple delegate.
• Example:
• Expression<Func<OrderLine, bool>> foo = (x) => x.Quantity > 10;
• Looks like simple lambda, but left side says that compiler should use Expression Tree instead of delegate
COLD QUERY EXECUTION PROCESS
Code User Writes Action Performance Impact
using(var db = new WideWorldImporters())
{
Context creation Low
var q1 =
from c in db. Orders
where c.Id == 1000
select c;
Query expression creation Low
var c1 = q1.First(); LINQ query execution - Metadata loading: High but cached
- View generation: Medium but cached
- Parameter evaluation: Low
- Query translation: Medium but cached
- Materializer generation: Medium but cached
- Database query execution: Potentially high (Better queries in some
situations)
+ Connection.Open
+ Command.ExecuteReader
+ DataReader.Read
Object materialization: Medium (Faster than EF5)
- Identity lookup: Medium
} Connection.Close Low
WARM QUERY EXECUTION PROCESS
Code User Writes Action Performance Impact
using(var db = new WideWorldImporters())
{
Context creation Low
var q1 =
from c in db. Orders
where c.Id == 1000
select c;
Query expression creation Low
var c1 = q1.First(); LINQ query execution - Metadata loading lookup: High but cached Low
- View generation lookup: Medium but cached Low
- Parameter evaluation: Low
- Query translation lookup: Medium but cached Low
- Materializer generation lookup: Medium but cached Low
- Database query execution: Potentially high (Better queries in some
situations)
+ Connection.Open
+ Command.ExecuteReader
+ DataReader.Read
Object materialization: Medium (Faster than EF5)
- Identity lookup: Medium
} Connection.Close Low
SOME USEFUL OPTIMIZATIONS
Find Find with AutoDetectChanges disabled
Find with AutoDetectChanges disabled
cached
Find 85491 3525 39
1
10
100
1000
10000
100000
Using DbSet<T>.Find
HOW EF CACHE WORKS
The cleanup algorithm is as follows:
• Once the cache contains a set number of entries (800), we start a timer that periodically (once-per-
minute) sweeps the cache.
• During cache sweeps, entries are removed from the cache on a LFRU (Least frequently – recently used)
basis. This algorithm takes both hit count and age into account when deciding which entries are
ejected.
• At the end of each cache sweep, the cache again contains 800 entries.
All cache entries are treated equally when determining which entries to evict. This means the store
command for a CompiledQuery has the same chance of eviction as the store command for an Entity SQL
query.
Note that the cache eviction timer is kicked in when there are 800 entities in the cache, but the cache is
only swept 60 seconds after this timer is started. That means that for up to 60 seconds your cache may
grow to be quite large.
CACHE TEST RESULTS
Test EF6 no cache EF6 cached
Enumerating all 18723 queries 124.3 125.3
Avoiding sweep (just the first 800 queries, regardless of complexity) 40.5 5.4
Just the AggregatingSubtotals queries (178 total - which avoids
sweep)
38.1 4.6
CONTAINS<T>
var ids = new int[10000];
...
using (var context = new WideWorldImporters("TestConString"))
{
var orders = context.Orders.Where(e => ids.Contains(e.CustomerID)).ToList();
...
}
PARAMETER SNIFFING
using (var context = new WideWorldImporters())
{
var myObject = new NonMappedType();
var query = from entity in context.Orders
where entity.CustomerPurchaseOrderNumber
.StartsWith(myObject.Mask)
select entity;
var results = query.ToList();
}
PARAMETER SNIFFING
using (var context = new WideWorldImporters())
{
var myObject = new NonMappedType();
var value = myObject.OrderNumberMask;
var query = from entity in context.Orders
where entity.CustomerPurchaseOrderNumber
.StartsWith(value)
select entity;
var results = query.ToList();
}
CACHING AGAIN
int[] ids = new int[10000];
using (var context = new WideWorldImporters())
{
var firstQuery = from c in context.Customers
where ids.Contains(c.CustomerId)
select c;
var secondQuery = from c in context.Customers
where firstQuery.Any(otherEntity => otherEntity.CustomerId == c.CustomerId)
select c;
var results = secondQuery.ToList();
}
LAZY LOAD
using (var context = new WideWorldImporters())
{
var customers = context.Customers.Include(e=>e.Orders)
.Where(c => c.BuyingGroup
.BuyingGroupName == "Tailspin Toys");
var chosenCustomer = customers.First();
Console.WriteLine("Customer Id: {0} has {1} orders",
chosenCustomer?.CustomerId,
chosenCustomer?.Orders.Count);
}
SELECT
[Project1].[BuyingGroupID1] AS [BuyingGroupID],
[Project1].[CustomerID] AS [CustomerID],
[Project1].[CustomerName] AS [CustomerName],
[Project1].[BillToCustomerID] AS [BillToCustomerID],
[Project1].[CustomerCategoryID] AS [CustomerCategoryID],
[Project1].[BuyingGroupID] AS [BuyingGroupID1],
[Project1].[PrimaryContactPersonID] AS [PrimaryContactPersonID],
[Project1].[AlternateContactPersonID] AS [AlternateContactPersonID],
[Project1].[DeliveryMethodID] AS [DeliveryMethodID],
[Project1].[DeliveryCityID] AS [DeliveryCityID],
[Project1].[PostalCityID] AS [PostalCityID],
[Project1].[CreditLimit] AS [CreditLimit],
[Project1].[AccountOpenedDate] AS [AccountOpenedDate],
[Project1].[StandardDiscountPercentage] AS [StandardDiscountPercentage],
[Project1].[IsStatementSent] AS [IsStatementSent],
[Project1].[IsOnCreditHold] AS [IsOnCreditHold],
[Project1].[PaymentDays] AS [PaymentDays],
[Project1].[PhoneNumber] AS [PhoneNumber],
[Project1].[FaxNumber] AS [FaxNumber],
[Project1].[DeliveryRun] AS [DeliveryRun],
[Project1].[RunPosition] AS [RunPosition],
[Project1].[WebsiteURL] AS [WebsiteURL],
[Project1].[DeliveryAddressLine1] AS [DeliveryAddressLine1],
[Project1].[DeliveryAddressLine2] AS [DeliveryAddressLine2],
[Project1].[DeliveryPostalCode] AS [DeliveryPostalCode],
[Project1].[PostalAddressLine1] AS [PostalAddressLine1],
[Project1].[PostalAddressLine2] AS [PostalAddressLine2],
[Project1].[PostalPostalCode] AS [PostalPostalCode],
[Project1].[LastEditedBy] AS [LastEditedBy],
[Project1].[ValidFrom] AS [ValidFrom],
[Project1].[ValidTo] AS [ValidTo],
[Project1].[C1] AS [C1],
[Project1].[OrderID] AS [OrderID],
[Project1].[CustomerID1] AS [CustomerID1],
[Project1].[SalespersonPersonID] AS [SalespersonPersonID],
[Project1].[PickedByPersonID] AS [PickedByPersonID],
[Project1].[ContactPersonID] AS [ContactPersonID],
[Project1].[BackorderOrderID] AS [BackorderOrderID],
[Project1].[OrderDate] AS [OrderDate],
[Project1].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate],
[Project1].[CustomerPurchaseOrderNumber] AS [CustomerPurchaseOrderNumber],
[Project1].[IsUndersupplyBackordered] AS [IsUndersupplyBackordered],
[Project1].[Comments] AS [Comments],
[Project1].[DeliveryInstructions] AS [DeliveryInstructions],
[Project1].[InternalComments] AS [InternalComments],
[Project1].[PickingCompletedWhen] AS [PickingCompletedWhen],
[Project1].[LastEditedBy1] AS [LastEditedBy1],
[Project1].[LastEditedWhen] AS [LastEditedWhen]
FROM ( SELECT
[Limit1].[CustomerID] AS [CustomerID],
[Limit1].[CustomerName] AS [CustomerName],
[Limit1].[BillToCustomerID] AS [BillToCustomerID],
[Limit1].[CustomerCategoryID] AS [CustomerCategoryID],
[Limit1].[BuyingGroupID1] AS [BuyingGroupID],
[Limit1].[PrimaryContactPersonID] AS [PrimaryContactPersonID],
[Limit1].[AlternateContactPersonID] AS [AlternateContactPersonID],
[Limit1].[DeliveryMethodID] AS [DeliveryMethodID],
[Limit1].[DeliveryCityID] AS [DeliveryCityID],
[Limit1].[PostalCityID] AS [PostalCityID],
[Limit1].[CreditLimit] AS [CreditLimit],
[Limit1].[AccountOpenedDate] AS [AccountOpenedDate],
[Limit1].[StandardDiscountPercentage] AS [StandardDiscountPercentage],
[Limit1].[IsStatementSent] AS [IsStatementSent],
[Limit1].[IsOnCreditHold] AS [IsOnCreditHold],
[Limit1].[PaymentDays] AS [PaymentDays],
[Limit1].[PhoneNumber] AS [PhoneNumber],
[Limit1].[FaxNumber] AS [FaxNumber],
[Limit1].[DeliveryRun] AS [DeliveryRun],
[Limit1].[RunPosition] AS [RunPosition],
[Limit1].[WebsiteURL] AS [WebsiteURL],
[Limit1].[DeliveryAddressLine1] AS [DeliveryAddressLine1],
[Limit1].[DeliveryAddressLine2] AS [DeliveryAddressLine2],
[Limit1].[DeliveryPostalCode] AS [DeliveryPostalCode],
[Limit1].[PostalAddressLine1] AS [PostalAddressLine1],
[Limit1].[PostalAddressLine2] AS [PostalAddressLine2],
[Limit1].[PostalPostalCode] AS [PostalPostalCode],
[Limit1].[LastEditedBy1] AS [LastEditedBy],
[Limit1].[ValidFrom1] AS [ValidFrom],
[Limit1].[ValidTo1] AS [ValidTo],
[Limit1].[BuyingGroupID2] AS [BuyingGroupID1],
[Extent3].[OrderID] AS [OrderID],
[Extent3].[CustomerID] AS [CustomerID1],
[Extent3].[SalespersonPersonID] AS [SalespersonPersonID],
[Extent3].[PickedByPersonID] AS [PickedByPersonID],
[Extent3].[ContactPersonID] AS [ContactPersonID],
[Extent3].[BackorderOrderID] AS [BackorderOrderID],
[Extent3].[OrderDate] AS [OrderDate],
[Extent3].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate],
[Extent3].[CustomerPurchaseOrderNumber] AS [CustomerPurchaseOrderNumber],
[Extent3].[IsUndersupplyBackordered] AS [IsUndersupplyBackordered],
[Extent3].[Comments] AS [Comments],
[Extent3].[DeliveryInstructions] AS [DeliveryInstructions],
[Extent3].[InternalComments] AS [InternalComments],
[Extent3].[PickingCompletedWhen] AS [PickingCompletedWhen],
[Extent3].[LastEditedBy] AS [LastEditedBy1],
[Extent3].[LastEditedWhen] AS [LastEditedWhen],
CASE WHEN ([Extent3].[OrderID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM (SELECT TOP (1) [Extent1].[CustomerID] AS [CustomerID],
[Extent1].[CustomerName] AS [CustomerName], [Extent1].[BillToCustomerID] AS
[BillToCustomerID], [Extent1].[CustomerCategoryID] AS [CustomerCategoryID],
[Extent1].[BuyingGroupID] AS [BuyingGroupID1], [Extent1].[PrimaryContactPersonID] AS
[PrimaryContactPersonID], [Extent1].[AlternateContactPersonID] AS
[AlternateContactPersonID], [Extent1].[DeliveryMethodID] AS [DeliveryMethodID],
[Extent1].[DeliveryCityID] AS [DeliveryCityID], [Extent1].[PostalCityID] AS [PostalCityID],
[Extent1].[CreditLimit] AS [CreditLimit], [Extent1].[AccountOpenedDate] AS
[AccountOpenedDate], [Extent1].[StandardDiscountPercentage] AS
[StandardDiscountPercentage], [Extent1].[IsStatementSent] AS [IsStatementSent],
[Extent1].[IsOnCreditHold] AS [IsOnCreditHold], [Extent1].[PaymentDays] AS [PaymentDays],
[Extent1].[PhoneNumber] AS [PhoneNumber], [Extent1].[FaxNumber] AS [FaxNumber],
[Extent1].[DeliveryRun] AS [DeliveryRun], [Extent1].[RunPosition] AS [RunPosition],
[Extent1].[WebsiteURL] AS [WebsiteURL], [Extent1].[DeliveryAddressLine1] AS
[DeliveryAddressLine1], [Extent1].[DeliveryAddressLine2] AS [DeliveryAddressLine2],
[Extent1].[DeliveryPostalCode] AS [DeliveryPostalCode], [Extent1].[PostalAddressLine1] AS
[PostalAddressLine1], [Extent1].[PostalAddressLine2] AS [PostalAddressLine2],
[Extent1].[PostalPostalCode] AS [PostalPostalCode], [Extent1].[LastEditedBy] AS
[LastEditedBy1], [Extent1].[ValidFrom] AS [ValidFrom1], [Extent1].[ValidTo] AS [ValidTo1],
[Extent2].[BuyingGroupID] AS [BuyingGroupID2]
FROM [Sales].[Customers] AS [Extent1]
INNER JOIN [Sales].[BuyingGroups] AS [Extent2] ON [Extent1].[BuyingGroupID] =
[Extent2].[BuyingGroupID]
WHERE N'Tailspin Toys' = [Extent2].[BuyingGroupName] ) AS [Limit1]
LEFT OUTER JOIN [Sales].[Orders] AS [Extent3] ON [Limit1].[CustomerID] =
[Extent3].[CustomerID]
) AS [Project1]
ORDER BY [Project1].[BuyingGroupID1] ASC, [Project1].[CustomerID] ASC, [Project1].[C1]
ASC
LAZY LOAD
using (var context = new WideWorldImporters())
{
var customers = context.Customers
.Where(c => c.BuyingGroup
.BuyingGroupName == "Tailspin Toys");
var chosenCustomer = customers.First();
Console.WriteLine("Customer Id: {0} has {1} orders",
chosenCustomer?.CustomerId,
chosenCustomer?.Orders.Count);
}
SELECT TOP (1)
[Extent1].[CustomerID] AS [CustomerID],
[Extent1].[CustomerName] AS [CustomerName],
[Extent1].[BillToCustomerID] AS [BillToCustomerID],
[Extent1].[CustomerCategoryID] AS [CustomerCategoryID],
[Extent1].[BuyingGroupID] AS [BuyingGroupID],
[Extent1].[PrimaryContactPersonID] AS [PrimaryContactPersonID],
[Extent1].[AlternateContactPersonID] AS [AlternateContactPersonID],
[Extent1].[DeliveryMethodID] AS [DeliveryMethodID],
[Extent1].[DeliveryCityID] AS [DeliveryCityID],
[Extent1].[PostalCityID] AS [PostalCityID],
[Extent1].[CreditLimit] AS [CreditLimit],
[Extent1].[AccountOpenedDate] AS [AccountOpenedDate],
[Extent1].[StandardDiscountPercentage] AS [StandardDiscountPercentage],
[Extent1].[IsStatementSent] AS [IsStatementSent],
[Extent1].[IsOnCreditHold] AS [IsOnCreditHold],
[Extent1].[PaymentDays] AS [PaymentDays],
[Extent1].[PhoneNumber] AS [PhoneNumber],
[Extent1].[FaxNumber] AS [FaxNumber],
[Extent1].[DeliveryRun] AS [DeliveryRun],
[Extent1].[RunPosition] AS [RunPosition],
[Extent1].[WebsiteURL] AS [WebsiteURL],
[Extent1].[DeliveryAddressLine1] AS [DeliveryAddressLine1],
[Extent1].[DeliveryAddressLine2] AS [DeliveryAddressLine2],
[Extent1].[DeliveryPostalCode] AS [DeliveryPostalCode],
[Extent1].[PostalAddressLine1] AS [PostalAddressLine1],
[Extent1].[PostalAddressLine2] AS [PostalAddressLine2],
[Extent1].[PostalPostalCode] AS [PostalPostalCode],
[Extent1].[LastEditedBy] AS [LastEditedBy],
[Extent1].[ValidFrom] AS [ValidFrom],
[Extent1].[ValidTo] AS [ValidTo]
FROM [Sales].[Customers] AS [Extent1]
INNER JOIN [Sales].[BuyingGroups] AS [Extent2] ON [Extent1].[BuyingGroupID] =
[Extent2].[BuyingGroupID]
WHERE N'Tailspin Toys' = [Extent2].[BuyingGroupName]
exec sp_executesql N'SELECT
[Extent1].[OrderID] AS [OrderID],
[Extent1].[CustomerID] AS [CustomerID],
[Extent1].[SalespersonPersonID] AS [SalespersonPersonID],
[Extent1].[PickedByPersonID] AS [PickedByPersonID],
[Extent1].[ContactPersonID] AS [ContactPersonID],
[Extent1].[BackorderOrderID] AS [BackorderOrderID],
[Extent1].[OrderDate] AS [OrderDate],
[Extent1].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate],
[Extent1].[CustomerPurchaseOrderNumber] AS
[CustomerPurchaseOrderNumber],
[Extent1].[IsUndersupplyBackordered] AS
[IsUndersupplyBackordered],
[Extent1].[Comments] AS [Comments],
[Extent1].[DeliveryInstructions] AS [DeliveryInstructions],
[Extent1].[InternalComments] AS [InternalComments],
[Extent1].[PickingCompletedWhen] AS [PickingCompletedWhen],
[Extent1].[LastEditedBy] AS [LastEditedBy],
[Extent1].[LastEditedWhen] AS [LastEditedWhen]
FROM [Sales].[Orders] AS [Extent1]
WHERE [Extent1].[CustomerID] =
@EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
DATA MODIFICATION
context.Customers
.Where(t => t.Name == “Petya”)
.Update(t => new Customer { Name = “Petya” });
PM> Install-Package EntityFramework.Extended
context.BulkInsert(customers);
PM> Install-Package Z.EntityFramework.Extensions
OOP
public class WideWorldImporters : DbContext
{
public WideWorldImporters(string conString) : base(conString)
{ }
// Some DbSets
}
OOP
public class WideWorldImporters : DbContext
{
public WideWorldImporters(string conString)
: base(conString) { }
public WideWorldImporters()
: this("WideWorldImporters") { }
// Some DbSets
}
using (var context = new WideWorldImport
ers("TestConString"))
{
context.Orders.ToList();
}
IF ORM IS SO BAD, WHAT’S SOLUTION?
Micro-ORM
• Handcraft SQL
• Handle mappings
• Less code (less functionality)
DAPPER
• Created for Stack Overflow
• Very. VERY fast
• Works with POCO and dynamics
using (var connection = new SqlConnection(conString))
{
var users = connection.Query<User>("select * from Users")
.ToList();
}
using (var connection = new SqlConnection(conString))
{
IEnumerable<dynamic> users = connection.Query ("select * from Users")
.ToList();
}
DAPPER. MAPPING
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 posts = data.ToList();
DAPPER. MULTI RESULTS
var sql = @" select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
}
DAPPER. PROCEDURES
var user = cnn.Query<User>(
"sp_GetUser",
new {Id = 1},
commandType: CommandType.StoredProcedure)
.SingleOrDefault();
DAPPER. OUTPUT PARAMETERS
var p = new DynamicParameters();
p.Add("@a", 11);
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
con.Execute(
"spMagicProc",
p,
commandType: CommandType.StoredProcedure);
int b = p.Get<int>("@b");
int c = p.Get<int>("@c");
PETAPOCO
Fast like Dapper
Works with strictly undecorated POCOs, or attributed almost-POCOs
var user1 = db.Single<User>(1);
var user2 = db.Single<User>("WHERE Name = @0", “Vasya");
PETAPOCO
var u = new User();
u.Name = “Vasya”;
db.Insert(u);
// Update it
u.Name = “Kolya";
db.Update(u);
// Delete it
db.Delete(u);
db.Delete<User>(
"WHERE Name LIKE @0",
“V%");
db.Update<User>(
"SET Name=@0 WHERE Id>@1",
“XXX",
10);
SIMPLE DATA
Fun project of @markrendle
Seems to be dead
But still is fun
return Database.Open()
.Users.FindAllByName(name)
.FirstOrDefault();
PERFORMANCE
SELECT MAPPING OVER 500
ITERATIONS - POCO SERIALIZATION
Method Duration
Hand coded (using a SqlDataReader) 47ms
Dapper ExecuteMapperQuery 49ms
PetaPoco 52ms
NHibernate SQL 104ms
Linq 2 SQL ExecuteQuery 181ms
Entity framework ExecuteStoreQuery 631ms
SELECT MAPPING OVER 500
ITERATIONS - DYNAMIC
SERIALIZATION
Method Duration
Dapper ExecuteMapperQuery (dynamic) 48ms
Simple.Data 95ms
CONCLUSIONS
• ORM good or bad? Depends.
• Micro-ORM is good alternative in cases when ORM is bad.
• Knowing internal implementations or behavior can increase performance of using
of the frameworks.
• You should always understand at least one layer below what you are coding.
Кирилл Безпалый, .NET Developer, Ciklum

More Related Content

What's hot (19)

Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in Realm
Yusuke Kita
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
Yakov Fain
 
Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1
Patrycja Wegrzynowicz
 
Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0
Oscar Renalias
 
Killing Shark-Riding Dinosaurs with ORM
Killing Shark-Riding Dinosaurs with ORMKilling Shark-Riding Dinosaurs with ORM
Killing Shark-Riding Dinosaurs with ORM
Ortus Solutions, Corp
 
Objective-C Is Not Java
Objective-C Is Not JavaObjective-C Is Not Java
Objective-C Is Not Java
Chris Adamson
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterprise
Rafael Bagmanov
 
Building Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with ScalaBuilding Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with Scala
WO Community
 
BOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala appsBOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala apps
Peter Pilgrim
 
Scala active record
Scala active recordScala active record
Scala active record
鉄平 土佐
 
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Thomas Vendetta
 
Short intro to scala and the play framework
Short intro to scala and the play frameworkShort intro to scala and the play framework
Short intro to scala and the play framework
Felipe
 
ERGroupware
ERGroupwareERGroupware
ERGroupware
WO Community
 
JavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development ExperiencesJavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development Experiences
Peter Pilgrim
 
Thinking Beyond ORM in JPA
Thinking Beyond ORM in JPAThinking Beyond ORM in JPA
Thinking Beyond ORM in JPA
Patrycja Wegrzynowicz
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
Kasun Indrasiri
 
The dark side of Akka and the remedy
The dark side of Akka and the remedyThe dark side of Akka and the remedy
The dark side of Akka and the remedy
krivachy
 
Groovy concurrency
Groovy concurrencyGroovy concurrency
Groovy concurrency
Alex Miller
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play Framework
Knoldus Inc.
 
Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in Realm
Yusuke Kita
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
Yakov Fain
 
Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1
Patrycja Wegrzynowicz
 
Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0
Oscar Renalias
 
Killing Shark-Riding Dinosaurs with ORM
Killing Shark-Riding Dinosaurs with ORMKilling Shark-Riding Dinosaurs with ORM
Killing Shark-Riding Dinosaurs with ORM
Ortus Solutions, Corp
 
Objective-C Is Not Java
Objective-C Is Not JavaObjective-C Is Not Java
Objective-C Is Not Java
Chris Adamson
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterprise
Rafael Bagmanov
 
Building Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with ScalaBuilding Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with Scala
WO Community
 
BOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala appsBOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala apps
Peter Pilgrim
 
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Integrate Ruby on Rails with Avectra's NetFORUM xWeb API.
Thomas Vendetta
 
Short intro to scala and the play framework
Short intro to scala and the play frameworkShort intro to scala and the play framework
Short intro to scala and the play framework
Felipe
 
JavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development ExperiencesJavaCro 2014 Scala and Java EE 7 Development Experiences
JavaCro 2014 Scala and Java EE 7 Development Experiences
Peter Pilgrim
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
Kasun Indrasiri
 
The dark side of Akka and the remedy
The dark side of Akka and the remedyThe dark side of Akka and the remedy
The dark side of Akka and the remedy
krivachy
 
Groovy concurrency
Groovy concurrencyGroovy concurrency
Groovy concurrency
Alex Miller
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play Framework
Knoldus Inc.
 

Similar to Кирилл Безпалый, .NET Developer, Ciklum (20)

Dapper performance
Dapper performanceDapper performance
Dapper performance
Suresh Loganatha
 
DDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVCDDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVC
Andy Butland
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
JAX London
 
Orms vs Micro-ORMs
Orms vs Micro-ORMsOrms vs Micro-ORMs
Orms vs Micro-ORMs
David Paquette
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
Eberhard Wolff
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service Clients
Daniel Ballinger
 
El camino a las Cloud Native Apps - Introduction
El camino a las Cloud Native Apps - IntroductionEl camino a las Cloud Native Apps - Introduction
El camino a las Cloud Native Apps - Introduction
Plain Concepts
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
smn-automate
 
SparkSQL: A Compiler from Queries to RDDs
SparkSQL: A Compiler from Queries to RDDsSparkSQL: A Compiler from Queries to RDDs
SparkSQL: A Compiler from Queries to RDDs
Databricks
 
Run Node Run
Run Node RunRun Node Run
Run Node Run
Kevin Swiber
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
Pascal Rettig
 
Introduction to mysql part 3
Introduction to mysql part 3Introduction to mysql part 3
Introduction to mysql part 3
baabtra.com - No. 1 supplier of quality freshers
 
Scaling asp.net websites to millions of users
Scaling asp.net websites to millions of usersScaling asp.net websites to millions of users
Scaling asp.net websites to millions of users
oazabir
 
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdfITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
Ortus Solutions, Corp
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']
Jan Helke
 
Oracle Drivers configuration for High Availability
Oracle Drivers configuration for High AvailabilityOracle Drivers configuration for High Availability
Oracle Drivers configuration for High Availability
Ludovico Caldara
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service Clients
Salesforce Developers
 
Nyc big datagenomics-pizarroa-sept2017
Nyc big datagenomics-pizarroa-sept2017Nyc big datagenomics-pizarroa-sept2017
Nyc big datagenomics-pizarroa-sept2017
delagoya
 
Web technologies-course 12.pptx
Web technologies-course 12.pptxWeb technologies-course 12.pptx
Web technologies-course 12.pptx
Stefan Oprea
 
WebObjects Optimization
WebObjects OptimizationWebObjects Optimization
WebObjects Optimization
WO Community
 
DDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVCDDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVC
Andy Butland
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
JAX London
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service Clients
Daniel Ballinger
 
El camino a las Cloud Native Apps - Introduction
El camino a las Cloud Native Apps - IntroductionEl camino a las Cloud Native Apps - Introduction
El camino a las Cloud Native Apps - Introduction
Plain Concepts
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
smn-automate
 
SparkSQL: A Compiler from Queries to RDDs
SparkSQL: A Compiler from Queries to RDDsSparkSQL: A Compiler from Queries to RDDs
SparkSQL: A Compiler from Queries to RDDs
Databricks
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
Pascal Rettig
 
Scaling asp.net websites to millions of users
Scaling asp.net websites to millions of usersScaling asp.net websites to millions of users
Scaling asp.net websites to millions of users
oazabir
 
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdfITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
ITB 2023 qb, Migration, Seeders. Recipe For Success - Gavin-Pickin.pdf
Ortus Solutions, Corp
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']
Jan Helke
 
Oracle Drivers configuration for High Availability
Oracle Drivers configuration for High AvailabilityOracle Drivers configuration for High Availability
Oracle Drivers configuration for High Availability
Ludovico Caldara
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service Clients
Salesforce Developers
 
Nyc big datagenomics-pizarroa-sept2017
Nyc big datagenomics-pizarroa-sept2017Nyc big datagenomics-pizarroa-sept2017
Nyc big datagenomics-pizarroa-sept2017
delagoya
 
Web technologies-course 12.pptx
Web technologies-course 12.pptxWeb technologies-course 12.pptx
Web technologies-course 12.pptx
Stefan Oprea
 
WebObjects Optimization
WebObjects OptimizationWebObjects Optimization
WebObjects Optimization
WO Community
 

More from Alina Vilk (20)

Designer in you, Irina Shapoval, Lead Designer, DataArt
Designer in you, Irina Shapoval, Lead Designer, DataArtDesigner in you, Irina Shapoval, Lead Designer, DataArt
Designer in you, Irina Shapoval, Lead Designer, DataArt
Alina Vilk
 
.NET framework vs .net core 3.1 commons &amp; differences
 .NET framework vs .net core 3.1  commons &amp; differences .NET framework vs .net core 3.1  commons &amp; differences
.NET framework vs .net core 3.1 commons &amp; differences
Alina Vilk
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
Alina Vilk
 
"Dev to PM" D.Fedotov
"Dev to PM" D.Fedotov"Dev to PM" D.Fedotov
"Dev to PM" D.Fedotov
Alina Vilk
 
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Alina Vilk
 
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt ) Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Alina Vilk
 
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Alina Vilk
 
Devops, v.02, Alexander Pavlenko (DataArt)
Devops, v.02, Alexander Pavlenko (DataArt)Devops, v.02, Alexander Pavlenko (DataArt)
Devops, v.02, Alexander Pavlenko (DataArt)
Alina Vilk
 
O DevOps, Stanislav Kolenkin ( DataArt)
O DevOps, Stanislav Kolenkin ( DataArt)O DevOps, Stanislav Kolenkin ( DataArt)
O DevOps, Stanislav Kolenkin ( DataArt)
Alina Vilk
 
Interactive 3D graphics for web with three.js, Andrey Vedilin, DataArt
Interactive  3D graphics for web with three.js, Andrey Vedilin, DataArtInteractive  3D graphics for web with three.js, Andrey Vedilin, DataArt
Interactive 3D graphics for web with three.js, Andrey Vedilin, DataArt
Alina Vilk
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Alina Vilk
 
Al around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Al around ML 2017, Оксана Савенко, студентка НТУ имени КаразинаAl around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Al around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Alina Vilk
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Alina Vilk
 
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo groupИгорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Alina Vilk
 
Александр Сергиенко, Senior Android Developer, DataArt
Александр Сергиенко, Senior Android Developer, DataArtАлександр Сергиенко, Senior Android Developer, DataArt
Александр Сергиенко, Senior Android Developer, DataArt
Alina Vilk
 
Евгений Дубовик, Senior Developer, DataArtDb presentation gdg
Евгений Дубовик, Senior Developer, DataArtDb presentation gdgЕвгений Дубовик, Senior Developer, DataArtDb presentation gdg
Евгений Дубовик, Senior Developer, DataArtDb presentation gdg
Alina Vilk
 
Дмитрий Козицкий,Lead UX / UI Designer, DataArt
Дмитрий Козицкий,Lead UX / UI Designer, DataArtДмитрий Козицкий,Lead UX / UI Designer, DataArt
Дмитрий Козицкий,Lead UX / UI Designer, DataArt
Alina Vilk
 
Игорь Юзовицкий,UX Expert, DataArt
Игорь Юзовицкий,UX Expert, DataArtИгорь Юзовицкий,UX Expert, DataArt
Игорь Юзовицкий,UX Expert, DataArt
Alina Vilk
 
Android Things, Alexey Rybakov, Technical Evangelist, DataArt
Android Things, Alexey Rybakov, Technical Evangelist, DataArtAndroid Things, Alexey Rybakov, Technical Evangelist, DataArt
Android Things, Alexey Rybakov, Technical Evangelist, DataArt
Alina Vilk
 
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
Alina Vilk
 
Designer in you, Irina Shapoval, Lead Designer, DataArt
Designer in you, Irina Shapoval, Lead Designer, DataArtDesigner in you, Irina Shapoval, Lead Designer, DataArt
Designer in you, Irina Shapoval, Lead Designer, DataArt
Alina Vilk
 
.NET framework vs .net core 3.1 commons &amp; differences
 .NET framework vs .net core 3.1  commons &amp; differences .NET framework vs .net core 3.1  commons &amp; differences
.NET framework vs .net core 3.1 commons &amp; differences
Alina Vilk
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
Alina Vilk
 
"Dev to PM" D.Fedotov
"Dev to PM" D.Fedotov"Dev to PM" D.Fedotov
"Dev to PM" D.Fedotov
Alina Vilk
 
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Игорь Литвиненко (Senior iOS- и Android-разработчик,DataArt)
Alina Vilk
 
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt ) Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Алексей Рыбаков (Senior Engineer,Technical Evangelist DataArt )
Alina Vilk
 
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Ирина Шаповал,(Lead UI/UX дизайнер, DataArt)
Alina Vilk
 
Devops, v.02, Alexander Pavlenko (DataArt)
Devops, v.02, Alexander Pavlenko (DataArt)Devops, v.02, Alexander Pavlenko (DataArt)
Devops, v.02, Alexander Pavlenko (DataArt)
Alina Vilk
 
O DevOps, Stanislav Kolenkin ( DataArt)
O DevOps, Stanislav Kolenkin ( DataArt)O DevOps, Stanislav Kolenkin ( DataArt)
O DevOps, Stanislav Kolenkin ( DataArt)
Alina Vilk
 
Interactive 3D graphics for web with three.js, Andrey Vedilin, DataArt
Interactive  3D graphics for web with three.js, Andrey Vedilin, DataArtInteractive  3D graphics for web with three.js, Andrey Vedilin, DataArt
Interactive 3D graphics for web with three.js, Andrey Vedilin, DataArt
Alina Vilk
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Alina Vilk
 
Al around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Al around ML 2017, Оксана Савенко, студентка НТУ имени КаразинаAl around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Al around ML 2017, Оксана Савенко, студентка НТУ имени Каразина
Alina Vilk
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Alina Vilk
 
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo groupИгорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Игорь Леонтьев, Lead Architect on all Blockchain projects of Viseo group
Alina Vilk
 
Александр Сергиенко, Senior Android Developer, DataArt
Александр Сергиенко, Senior Android Developer, DataArtАлександр Сергиенко, Senior Android Developer, DataArt
Александр Сергиенко, Senior Android Developer, DataArt
Alina Vilk
 
Евгений Дубовик, Senior Developer, DataArtDb presentation gdg
Евгений Дубовик, Senior Developer, DataArtDb presentation gdgЕвгений Дубовик, Senior Developer, DataArtDb presentation gdg
Евгений Дубовик, Senior Developer, DataArtDb presentation gdg
Alina Vilk
 
Дмитрий Козицкий,Lead UX / UI Designer, DataArt
Дмитрий Козицкий,Lead UX / UI Designer, DataArtДмитрий Козицкий,Lead UX / UI Designer, DataArt
Дмитрий Козицкий,Lead UX / UI Designer, DataArt
Alina Vilk
 
Игорь Юзовицкий,UX Expert, DataArt
Игорь Юзовицкий,UX Expert, DataArtИгорь Юзовицкий,UX Expert, DataArt
Игорь Юзовицкий,UX Expert, DataArt
Alina Vilk
 
Android Things, Alexey Rybakov, Technical Evangelist, DataArt
Android Things, Alexey Rybakov, Technical Evangelist, DataArtAndroid Things, Alexey Rybakov, Technical Evangelist, DataArt
Android Things, Alexey Rybakov, Technical Evangelist, DataArt
Alina Vilk
 
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
«Делегирование как идеальный способ угробить проект», Александр Ивахненко, IT...
Alina Vilk
 

Recently uploaded (20)

The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...
Sandeep Swamy
 
Odoo Inventory Rules and Routes v17 - Odoo Slides
Odoo Inventory Rules and Routes v17 - Odoo SlidesOdoo Inventory Rules and Routes v17 - Odoo Slides
Odoo Inventory Rules and Routes v17 - Odoo Slides
Celine George
 
To study Digestive system of insect.pptx
To study Digestive system of insect.pptxTo study Digestive system of insect.pptx
To study Digestive system of insect.pptx
Arshad Shaikh
 
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
larencebapu132
 
Multi-currency in odoo accounting and Update exchange rates automatically in ...
Multi-currency in odoo accounting and Update exchange rates automatically in ...Multi-currency in odoo accounting and Update exchange rates automatically in ...
Multi-currency in odoo accounting and Update exchange rates automatically in ...
Celine George
 
How to Subscribe Newsletter From Odoo 18 Website
How to Subscribe Newsletter From Odoo 18 WebsiteHow to Subscribe Newsletter From Odoo 18 Website
How to Subscribe Newsletter From Odoo 18 Website
Celine George
 
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Library Association of Ireland
 
Handling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptxHandling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptx
AuthorAIDNationalRes
 
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACYUNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
DR.PRISCILLA MARY J
 
Operations Management (Dr. Abdulfatah Salem).pdf
Operations Management (Dr. Abdulfatah Salem).pdfOperations Management (Dr. Abdulfatah Salem).pdf
Operations Management (Dr. Abdulfatah Salem).pdf
Arab Academy for Science, Technology and Maritime Transport
 
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Library Association of Ireland
 
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 AccountingHow to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
Celine George
 
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptxSCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
Ronisha Das
 
SPRING FESTIVITIES - UK AND USA -
SPRING FESTIVITIES - UK AND USA            -SPRING FESTIVITIES - UK AND USA            -
SPRING FESTIVITIES - UK AND USA -
Colégio Santa Teresinha
 
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - WorksheetCBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
Sritoma Majumder
 
YSPH VMOC Special Report - Measles Outbreak Southwest US 5-3-2025.pptx
YSPH VMOC Special Report - Measles Outbreak  Southwest US 5-3-2025.pptxYSPH VMOC Special Report - Measles Outbreak  Southwest US 5-3-2025.pptx
YSPH VMOC Special Report - Measles Outbreak Southwest US 5-3-2025.pptx
Yale School of Public Health - The Virtual Medical Operations Center (VMOC)
 
YSPH VMOC Special Report - Measles Outbreak Southwest US 4-30-2025.pptx
YSPH VMOC Special Report - Measles Outbreak  Southwest US 4-30-2025.pptxYSPH VMOC Special Report - Measles Outbreak  Southwest US 4-30-2025.pptx
YSPH VMOC Special Report - Measles Outbreak Southwest US 4-30-2025.pptx
Yale School of Public Health - The Virtual Medical Operations Center (VMOC)
 
Understanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s GuideUnderstanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s Guide
GS Virdi
 
Anti-Depressants pharmacology 1slide.pptx
Anti-Depressants pharmacology 1slide.pptxAnti-Depressants pharmacology 1slide.pptx
Anti-Depressants pharmacology 1slide.pptx
Mayuri Chavan
 
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
Celine George
 
The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...
Sandeep Swamy
 
Odoo Inventory Rules and Routes v17 - Odoo Slides
Odoo Inventory Rules and Routes v17 - Odoo SlidesOdoo Inventory Rules and Routes v17 - Odoo Slides
Odoo Inventory Rules and Routes v17 - Odoo Slides
Celine George
 
To study Digestive system of insect.pptx
To study Digestive system of insect.pptxTo study Digestive system of insect.pptx
To study Digestive system of insect.pptx
Arshad Shaikh
 
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
larencebapu132
 
Multi-currency in odoo accounting and Update exchange rates automatically in ...
Multi-currency in odoo accounting and Update exchange rates automatically in ...Multi-currency in odoo accounting and Update exchange rates automatically in ...
Multi-currency in odoo accounting and Update exchange rates automatically in ...
Celine George
 
How to Subscribe Newsletter From Odoo 18 Website
How to Subscribe Newsletter From Odoo 18 WebsiteHow to Subscribe Newsletter From Odoo 18 Website
How to Subscribe Newsletter From Odoo 18 Website
Celine George
 
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Phoenix – A Collaborative Renewal of Children’s and Young People’s Services C...
Library Association of Ireland
 
Handling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptxHandling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptx
AuthorAIDNationalRes
 
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACYUNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
UNIT 3 NATIONAL HEALTH PROGRAMMEE. SOCIAL AND PREVENTIVE PHARMACY
DR.PRISCILLA MARY J
 
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Marie Boran Special Collections Librarian Hardiman Library, University of Gal...
Library Association of Ireland
 
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 AccountingHow to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
Celine George
 
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptxSCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
SCI BIZ TECH QUIZ (OPEN) PRELIMS XTASY 2025.pptx
Ronisha Das
 
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - WorksheetCBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
Sritoma Majumder
 
Understanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s GuideUnderstanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s Guide
GS Virdi
 
Anti-Depressants pharmacology 1slide.pptx
Anti-Depressants pharmacology 1slide.pptxAnti-Depressants pharmacology 1slide.pptx
Anti-Depressants pharmacology 1slide.pptx
Mayuri Chavan
 
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
Celine George
 

Кирилл Безпалый, .NET Developer, Ciklum

  • 1. ORM OR NOT ORM? THAT IS THE QUESTION BEZPALYI KYRYLO, .NET DEVELOPER @ CIKLUM
  • 2. ABOUT ME • .Net developer @ Ciklum • Microsoft Student Partner • An avid programmer
  • 3. BEFORE WE BEGIN ALL NON-TRIVIAL ABSTRACTIONS, TO SOME DEGREE, ARE LEAKY. Joel Spolsky, The Law of Leaky Abstractions YOU SHOULD ALWAYS UNDERSTAND AT LEAST ONE LAYER BELOW WHAT YOU ARE CODING. Lee Campbell, author of IntroToRX.com
  • 4. SMALL HISTORY • ADO.NET • Data Sets • Strong-typed Data Sets • NHibernate • LINQ to SQL • Entity Framework • EF Code First • EF Core
  • 5. WHAT IS .NET WAY TODAY? • .NET • ASP.NET (WebApi/MVC) • Sql Server • Entity Framework
  • 6. WHAT’S .NET DEVELOPERS THINK ABOUT EF? • Too much configuration (Fluent API, attributes, navigation properties, keys, relations, etc.) • Leaking abstractions (LINQ) • Object model does not fit business model • Things become complicated very fast
  • 8. PROBLEM OF ENTITY FRAMEWORK • Performance • Parameter Sniffing • Lazy Load • Data Modification • Some crazy stuff
  • 10. HIDDEN POTENTIAN IQUERYABLE • Do you know difference between IEnumerable and IQueryable. Lot of tutorials don`t show full power of IQueryable showing only some simple examples. • In practice: IQueryable has generic logic of query using Expression Trees data structure and Provider that can transform this logic in query to some data source.
  • 11. MORE ABOUT EXPRESSION TREE • Expression tree it’s a tree of operations and their operands which can be other operations • Generally Expression tree is a serialized code • Difference between IEnumerable and IQueryable: • IEnumerable represent sequence of values, values processed by delegates • IQueryable represent query collected with Expression Tree • Expressions has deep integration in VS, so in some cases programmers don’t understand that their lambda will be converted to some data structure instead of simple delegate. • Example: • Expression<Func<OrderLine, bool>> foo = (x) => x.Quantity > 10; • Looks like simple lambda, but left side says that compiler should use Expression Tree instead of delegate
  • 12. COLD QUERY EXECUTION PROCESS Code User Writes Action Performance Impact using(var db = new WideWorldImporters()) { Context creation Low var q1 = from c in db. Orders where c.Id == 1000 select c; Query expression creation Low var c1 = q1.First(); LINQ query execution - Metadata loading: High but cached - View generation: Medium but cached - Parameter evaluation: Low - Query translation: Medium but cached - Materializer generation: Medium but cached - Database query execution: Potentially high (Better queries in some situations) + Connection.Open + Command.ExecuteReader + DataReader.Read Object materialization: Medium (Faster than EF5) - Identity lookup: Medium } Connection.Close Low
  • 13. WARM QUERY EXECUTION PROCESS Code User Writes Action Performance Impact using(var db = new WideWorldImporters()) { Context creation Low var q1 = from c in db. Orders where c.Id == 1000 select c; Query expression creation Low var c1 = q1.First(); LINQ query execution - Metadata loading lookup: High but cached Low - View generation lookup: Medium but cached Low - Parameter evaluation: Low - Query translation lookup: Medium but cached Low - Materializer generation lookup: Medium but cached Low - Database query execution: Potentially high (Better queries in some situations) + Connection.Open + Command.ExecuteReader + DataReader.Read Object materialization: Medium (Faster than EF5) - Identity lookup: Medium } Connection.Close Low
  • 14. SOME USEFUL OPTIMIZATIONS Find Find with AutoDetectChanges disabled Find with AutoDetectChanges disabled cached Find 85491 3525 39 1 10 100 1000 10000 100000 Using DbSet<T>.Find
  • 15. HOW EF CACHE WORKS The cleanup algorithm is as follows: • Once the cache contains a set number of entries (800), we start a timer that periodically (once-per- minute) sweeps the cache. • During cache sweeps, entries are removed from the cache on a LFRU (Least frequently – recently used) basis. This algorithm takes both hit count and age into account when deciding which entries are ejected. • At the end of each cache sweep, the cache again contains 800 entries. All cache entries are treated equally when determining which entries to evict. This means the store command for a CompiledQuery has the same chance of eviction as the store command for an Entity SQL query. Note that the cache eviction timer is kicked in when there are 800 entities in the cache, but the cache is only swept 60 seconds after this timer is started. That means that for up to 60 seconds your cache may grow to be quite large.
  • 16. CACHE TEST RESULTS Test EF6 no cache EF6 cached Enumerating all 18723 queries 124.3 125.3 Avoiding sweep (just the first 800 queries, regardless of complexity) 40.5 5.4 Just the AggregatingSubtotals queries (178 total - which avoids sweep) 38.1 4.6
  • 17. CONTAINS<T> var ids = new int[10000]; ... using (var context = new WideWorldImporters("TestConString")) { var orders = context.Orders.Where(e => ids.Contains(e.CustomerID)).ToList(); ... }
  • 18. PARAMETER SNIFFING using (var context = new WideWorldImporters()) { var myObject = new NonMappedType(); var query = from entity in context.Orders where entity.CustomerPurchaseOrderNumber .StartsWith(myObject.Mask) select entity; var results = query.ToList(); }
  • 19. PARAMETER SNIFFING using (var context = new WideWorldImporters()) { var myObject = new NonMappedType(); var value = myObject.OrderNumberMask; var query = from entity in context.Orders where entity.CustomerPurchaseOrderNumber .StartsWith(value) select entity; var results = query.ToList(); }
  • 20. CACHING AGAIN int[] ids = new int[10000]; using (var context = new WideWorldImporters()) { var firstQuery = from c in context.Customers where ids.Contains(c.CustomerId) select c; var secondQuery = from c in context.Customers where firstQuery.Any(otherEntity => otherEntity.CustomerId == c.CustomerId) select c; var results = secondQuery.ToList(); }
  • 21. LAZY LOAD using (var context = new WideWorldImporters()) { var customers = context.Customers.Include(e=>e.Orders) .Where(c => c.BuyingGroup .BuyingGroupName == "Tailspin Toys"); var chosenCustomer = customers.First(); Console.WriteLine("Customer Id: {0} has {1} orders", chosenCustomer?.CustomerId, chosenCustomer?.Orders.Count); }
  • 22. SELECT [Project1].[BuyingGroupID1] AS [BuyingGroupID], [Project1].[CustomerID] AS [CustomerID], [Project1].[CustomerName] AS [CustomerName], [Project1].[BillToCustomerID] AS [BillToCustomerID], [Project1].[CustomerCategoryID] AS [CustomerCategoryID], [Project1].[BuyingGroupID] AS [BuyingGroupID1], [Project1].[PrimaryContactPersonID] AS [PrimaryContactPersonID], [Project1].[AlternateContactPersonID] AS [AlternateContactPersonID], [Project1].[DeliveryMethodID] AS [DeliveryMethodID], [Project1].[DeliveryCityID] AS [DeliveryCityID], [Project1].[PostalCityID] AS [PostalCityID], [Project1].[CreditLimit] AS [CreditLimit], [Project1].[AccountOpenedDate] AS [AccountOpenedDate], [Project1].[StandardDiscountPercentage] AS [StandardDiscountPercentage], [Project1].[IsStatementSent] AS [IsStatementSent], [Project1].[IsOnCreditHold] AS [IsOnCreditHold], [Project1].[PaymentDays] AS [PaymentDays], [Project1].[PhoneNumber] AS [PhoneNumber], [Project1].[FaxNumber] AS [FaxNumber], [Project1].[DeliveryRun] AS [DeliveryRun], [Project1].[RunPosition] AS [RunPosition], [Project1].[WebsiteURL] AS [WebsiteURL], [Project1].[DeliveryAddressLine1] AS [DeliveryAddressLine1], [Project1].[DeliveryAddressLine2] AS [DeliveryAddressLine2], [Project1].[DeliveryPostalCode] AS [DeliveryPostalCode], [Project1].[PostalAddressLine1] AS [PostalAddressLine1], [Project1].[PostalAddressLine2] AS [PostalAddressLine2], [Project1].[PostalPostalCode] AS [PostalPostalCode], [Project1].[LastEditedBy] AS [LastEditedBy], [Project1].[ValidFrom] AS [ValidFrom], [Project1].[ValidTo] AS [ValidTo], [Project1].[C1] AS [C1], [Project1].[OrderID] AS [OrderID], [Project1].[CustomerID1] AS [CustomerID1], [Project1].[SalespersonPersonID] AS [SalespersonPersonID], [Project1].[PickedByPersonID] AS [PickedByPersonID], [Project1].[ContactPersonID] AS [ContactPersonID], [Project1].[BackorderOrderID] AS [BackorderOrderID], [Project1].[OrderDate] AS [OrderDate], [Project1].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate], [Project1].[CustomerPurchaseOrderNumber] AS [CustomerPurchaseOrderNumber], [Project1].[IsUndersupplyBackordered] AS [IsUndersupplyBackordered], [Project1].[Comments] AS [Comments], [Project1].[DeliveryInstructions] AS [DeliveryInstructions], [Project1].[InternalComments] AS [InternalComments], [Project1].[PickingCompletedWhen] AS [PickingCompletedWhen], [Project1].[LastEditedBy1] AS [LastEditedBy1], [Project1].[LastEditedWhen] AS [LastEditedWhen] FROM ( SELECT [Limit1].[CustomerID] AS [CustomerID], [Limit1].[CustomerName] AS [CustomerName], [Limit1].[BillToCustomerID] AS [BillToCustomerID], [Limit1].[CustomerCategoryID] AS [CustomerCategoryID], [Limit1].[BuyingGroupID1] AS [BuyingGroupID], [Limit1].[PrimaryContactPersonID] AS [PrimaryContactPersonID], [Limit1].[AlternateContactPersonID] AS [AlternateContactPersonID], [Limit1].[DeliveryMethodID] AS [DeliveryMethodID], [Limit1].[DeliveryCityID] AS [DeliveryCityID], [Limit1].[PostalCityID] AS [PostalCityID], [Limit1].[CreditLimit] AS [CreditLimit], [Limit1].[AccountOpenedDate] AS [AccountOpenedDate], [Limit1].[StandardDiscountPercentage] AS [StandardDiscountPercentage], [Limit1].[IsStatementSent] AS [IsStatementSent], [Limit1].[IsOnCreditHold] AS [IsOnCreditHold], [Limit1].[PaymentDays] AS [PaymentDays], [Limit1].[PhoneNumber] AS [PhoneNumber], [Limit1].[FaxNumber] AS [FaxNumber], [Limit1].[DeliveryRun] AS [DeliveryRun], [Limit1].[RunPosition] AS [RunPosition], [Limit1].[WebsiteURL] AS [WebsiteURL], [Limit1].[DeliveryAddressLine1] AS [DeliveryAddressLine1], [Limit1].[DeliveryAddressLine2] AS [DeliveryAddressLine2], [Limit1].[DeliveryPostalCode] AS [DeliveryPostalCode], [Limit1].[PostalAddressLine1] AS [PostalAddressLine1], [Limit1].[PostalAddressLine2] AS [PostalAddressLine2], [Limit1].[PostalPostalCode] AS [PostalPostalCode], [Limit1].[LastEditedBy1] AS [LastEditedBy], [Limit1].[ValidFrom1] AS [ValidFrom], [Limit1].[ValidTo1] AS [ValidTo], [Limit1].[BuyingGroupID2] AS [BuyingGroupID1], [Extent3].[OrderID] AS [OrderID], [Extent3].[CustomerID] AS [CustomerID1], [Extent3].[SalespersonPersonID] AS [SalespersonPersonID], [Extent3].[PickedByPersonID] AS [PickedByPersonID], [Extent3].[ContactPersonID] AS [ContactPersonID], [Extent3].[BackorderOrderID] AS [BackorderOrderID], [Extent3].[OrderDate] AS [OrderDate], [Extent3].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate], [Extent3].[CustomerPurchaseOrderNumber] AS [CustomerPurchaseOrderNumber], [Extent3].[IsUndersupplyBackordered] AS [IsUndersupplyBackordered], [Extent3].[Comments] AS [Comments], [Extent3].[DeliveryInstructions] AS [DeliveryInstructions], [Extent3].[InternalComments] AS [InternalComments], [Extent3].[PickingCompletedWhen] AS [PickingCompletedWhen], [Extent3].[LastEditedBy] AS [LastEditedBy1], [Extent3].[LastEditedWhen] AS [LastEditedWhen], CASE WHEN ([Extent3].[OrderID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM (SELECT TOP (1) [Extent1].[CustomerID] AS [CustomerID], [Extent1].[CustomerName] AS [CustomerName], [Extent1].[BillToCustomerID] AS [BillToCustomerID], [Extent1].[CustomerCategoryID] AS [CustomerCategoryID], [Extent1].[BuyingGroupID] AS [BuyingGroupID1], [Extent1].[PrimaryContactPersonID] AS [PrimaryContactPersonID], [Extent1].[AlternateContactPersonID] AS [AlternateContactPersonID], [Extent1].[DeliveryMethodID] AS [DeliveryMethodID], [Extent1].[DeliveryCityID] AS [DeliveryCityID], [Extent1].[PostalCityID] AS [PostalCityID], [Extent1].[CreditLimit] AS [CreditLimit], [Extent1].[AccountOpenedDate] AS [AccountOpenedDate], [Extent1].[StandardDiscountPercentage] AS [StandardDiscountPercentage], [Extent1].[IsStatementSent] AS [IsStatementSent], [Extent1].[IsOnCreditHold] AS [IsOnCreditHold], [Extent1].[PaymentDays] AS [PaymentDays], [Extent1].[PhoneNumber] AS [PhoneNumber], [Extent1].[FaxNumber] AS [FaxNumber], [Extent1].[DeliveryRun] AS [DeliveryRun], [Extent1].[RunPosition] AS [RunPosition], [Extent1].[WebsiteURL] AS [WebsiteURL], [Extent1].[DeliveryAddressLine1] AS [DeliveryAddressLine1], [Extent1].[DeliveryAddressLine2] AS [DeliveryAddressLine2], [Extent1].[DeliveryPostalCode] AS [DeliveryPostalCode], [Extent1].[PostalAddressLine1] AS [PostalAddressLine1], [Extent1].[PostalAddressLine2] AS [PostalAddressLine2], [Extent1].[PostalPostalCode] AS [PostalPostalCode], [Extent1].[LastEditedBy] AS [LastEditedBy1], [Extent1].[ValidFrom] AS [ValidFrom1], [Extent1].[ValidTo] AS [ValidTo1], [Extent2].[BuyingGroupID] AS [BuyingGroupID2] FROM [Sales].[Customers] AS [Extent1] INNER JOIN [Sales].[BuyingGroups] AS [Extent2] ON [Extent1].[BuyingGroupID] = [Extent2].[BuyingGroupID] WHERE N'Tailspin Toys' = [Extent2].[BuyingGroupName] ) AS [Limit1] LEFT OUTER JOIN [Sales].[Orders] AS [Extent3] ON [Limit1].[CustomerID] = [Extent3].[CustomerID] ) AS [Project1] ORDER BY [Project1].[BuyingGroupID1] ASC, [Project1].[CustomerID] ASC, [Project1].[C1] ASC
  • 23. LAZY LOAD using (var context = new WideWorldImporters()) { var customers = context.Customers .Where(c => c.BuyingGroup .BuyingGroupName == "Tailspin Toys"); var chosenCustomer = customers.First(); Console.WriteLine("Customer Id: {0} has {1} orders", chosenCustomer?.CustomerId, chosenCustomer?.Orders.Count); }
  • 24. SELECT TOP (1) [Extent1].[CustomerID] AS [CustomerID], [Extent1].[CustomerName] AS [CustomerName], [Extent1].[BillToCustomerID] AS [BillToCustomerID], [Extent1].[CustomerCategoryID] AS [CustomerCategoryID], [Extent1].[BuyingGroupID] AS [BuyingGroupID], [Extent1].[PrimaryContactPersonID] AS [PrimaryContactPersonID], [Extent1].[AlternateContactPersonID] AS [AlternateContactPersonID], [Extent1].[DeliveryMethodID] AS [DeliveryMethodID], [Extent1].[DeliveryCityID] AS [DeliveryCityID], [Extent1].[PostalCityID] AS [PostalCityID], [Extent1].[CreditLimit] AS [CreditLimit], [Extent1].[AccountOpenedDate] AS [AccountOpenedDate], [Extent1].[StandardDiscountPercentage] AS [StandardDiscountPercentage], [Extent1].[IsStatementSent] AS [IsStatementSent], [Extent1].[IsOnCreditHold] AS [IsOnCreditHold], [Extent1].[PaymentDays] AS [PaymentDays], [Extent1].[PhoneNumber] AS [PhoneNumber], [Extent1].[FaxNumber] AS [FaxNumber], [Extent1].[DeliveryRun] AS [DeliveryRun], [Extent1].[RunPosition] AS [RunPosition], [Extent1].[WebsiteURL] AS [WebsiteURL], [Extent1].[DeliveryAddressLine1] AS [DeliveryAddressLine1], [Extent1].[DeliveryAddressLine2] AS [DeliveryAddressLine2], [Extent1].[DeliveryPostalCode] AS [DeliveryPostalCode], [Extent1].[PostalAddressLine1] AS [PostalAddressLine1], [Extent1].[PostalAddressLine2] AS [PostalAddressLine2], [Extent1].[PostalPostalCode] AS [PostalPostalCode], [Extent1].[LastEditedBy] AS [LastEditedBy], [Extent1].[ValidFrom] AS [ValidFrom], [Extent1].[ValidTo] AS [ValidTo] FROM [Sales].[Customers] AS [Extent1] INNER JOIN [Sales].[BuyingGroups] AS [Extent2] ON [Extent1].[BuyingGroupID] = [Extent2].[BuyingGroupID] WHERE N'Tailspin Toys' = [Extent2].[BuyingGroupName] exec sp_executesql N'SELECT [Extent1].[OrderID] AS [OrderID], [Extent1].[CustomerID] AS [CustomerID], [Extent1].[SalespersonPersonID] AS [SalespersonPersonID], [Extent1].[PickedByPersonID] AS [PickedByPersonID], [Extent1].[ContactPersonID] AS [ContactPersonID], [Extent1].[BackorderOrderID] AS [BackorderOrderID], [Extent1].[OrderDate] AS [OrderDate], [Extent1].[ExpectedDeliveryDate] AS [ExpectedDeliveryDate], [Extent1].[CustomerPurchaseOrderNumber] AS [CustomerPurchaseOrderNumber], [Extent1].[IsUndersupplyBackordered] AS [IsUndersupplyBackordered], [Extent1].[Comments] AS [Comments], [Extent1].[DeliveryInstructions] AS [DeliveryInstructions], [Extent1].[InternalComments] AS [InternalComments], [Extent1].[PickingCompletedWhen] AS [PickingCompletedWhen], [Extent1].[LastEditedBy] AS [LastEditedBy], [Extent1].[LastEditedWhen] AS [LastEditedWhen] FROM [Sales].[Orders] AS [Extent1] WHERE [Extent1].[CustomerID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
  • 25. DATA MODIFICATION context.Customers .Where(t => t.Name == “Petya”) .Update(t => new Customer { Name = “Petya” }); PM> Install-Package EntityFramework.Extended context.BulkInsert(customers); PM> Install-Package Z.EntityFramework.Extensions
  • 26. OOP public class WideWorldImporters : DbContext { public WideWorldImporters(string conString) : base(conString) { } // Some DbSets }
  • 27. OOP public class WideWorldImporters : DbContext { public WideWorldImporters(string conString) : base(conString) { } public WideWorldImporters() : this("WideWorldImporters") { } // Some DbSets } using (var context = new WideWorldImport ers("TestConString")) { context.Orders.ToList(); }
  • 28. IF ORM IS SO BAD, WHAT’S SOLUTION? Micro-ORM • Handcraft SQL • Handle mappings • Less code (less functionality)
  • 29. DAPPER • Created for Stack Overflow • Very. VERY fast • Works with POCO and dynamics using (var connection = new SqlConnection(conString)) { var users = connection.Query<User>("select * from Users") .ToList(); } using (var connection = new SqlConnection(conString)) { IEnumerable<dynamic> users = connection.Query ("select * from Users") .ToList(); }
  • 30. DAPPER. MAPPING 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 posts = data.ToList();
  • 31. DAPPER. MULTI RESULTS var sql = @" select * from Customers where CustomerId = @id select * from Orders where CustomerId = @id select * from Returns where CustomerId = @id"; using (var multi = connection.QueryMultiple(sql, new {id=selectedId})) { var customer = multi.Read<Customer>().Single(); var orders = multi.Read<Order>().ToList(); var returns = multi.Read<Return>().ToList(); }
  • 32. DAPPER. PROCEDURES var user = cnn.Query<User>( "sp_GetUser", new {Id = 1}, commandType: CommandType.StoredProcedure) .SingleOrDefault();
  • 33. DAPPER. OUTPUT PARAMETERS var p = new DynamicParameters(); p.Add("@a", 11); p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); con.Execute( "spMagicProc", p, commandType: CommandType.StoredProcedure); int b = p.Get<int>("@b"); int c = p.Get<int>("@c");
  • 34. PETAPOCO Fast like Dapper Works with strictly undecorated POCOs, or attributed almost-POCOs var user1 = db.Single<User>(1); var user2 = db.Single<User>("WHERE Name = @0", “Vasya");
  • 35. PETAPOCO var u = new User(); u.Name = “Vasya”; db.Insert(u); // Update it u.Name = “Kolya"; db.Update(u); // Delete it db.Delete(u); db.Delete<User>( "WHERE Name LIKE @0", “V%"); db.Update<User>( "SET Name=@0 WHERE Id>@1", “XXX", 10);
  • 36. SIMPLE DATA Fun project of @markrendle Seems to be dead But still is fun return Database.Open() .Users.FindAllByName(name) .FirstOrDefault();
  • 37. PERFORMANCE SELECT MAPPING OVER 500 ITERATIONS - POCO SERIALIZATION Method Duration Hand coded (using a SqlDataReader) 47ms Dapper ExecuteMapperQuery 49ms PetaPoco 52ms NHibernate SQL 104ms Linq 2 SQL ExecuteQuery 181ms Entity framework ExecuteStoreQuery 631ms SELECT MAPPING OVER 500 ITERATIONS - DYNAMIC SERIALIZATION Method Duration Dapper ExecuteMapperQuery (dynamic) 48ms Simple.Data 95ms
  • 38. CONCLUSIONS • ORM good or bad? Depends. • Micro-ORM is good alternative in cases when ORM is bad. • Knowing internal implementations or behavior can increase performance of using of the frameworks. • You should always understand at least one layer below what you are coding.