Simple Data
Simple.Data is dynamic ORM. But What mean ORM : O – object, R – Relational, M – Mapping. But if simple data is dynamic we haven’t objects, relationals, mapping. So try again “Simple.Data is dynamic (NullReferenceException)” – weak joke 😉
Today I will try to compare Simple.Data with EntityFramework.
Example
The example uses two tables “team” and “players”
For example code has been written in console and to measure execution time I use Stopwatch class. It’s look like:
static void Main(string[] args) { do { var timer = new Stopwatch(); timer.Start(); SimpleDataClass.GetTableBySD(); timer.Stop(); Console.WriteLine("Test with Simple.Data " + string.Format("{0:0.000}", 1000.0 * timer.ElapsedTicks / Stopwatch.Frequency) + " ms\n"); var timer2 = new Stopwatch(); timer2.Start(); ORM.GetTableByORM(); timer2.Stop(); Console.WriteLine("Test with EF " + string.Format("{0:0.000}", 1000.0 * timer2.ElapsedTicks / Stopwatch.Frequency)+ " ms\n"); } while (Console.ReadKey(true).Key != ConsoleKey.Z); }
Loading data
Let’s try to load data from database with Simple.Data. It’s so simple, we serve as parametr our connection string to our database in method .OpenConnection() we can also use .Open() method if we configured connection string in App.Config. Method defaultDb.Team.All() return all records from table team.
public class SimpleDataClass { public static void GetTableBySD() { string ConnectionString = @"Data Source = PAWEL; Initial Catalog = test; Integrated Security = True"; dynamic defaultDb = Database.OpenConnection(ConnectionString); var list = defaultDb.team.All(); } }
And the same in Entity Framework.
public class ORM { public static void GetTableByORM() { using (testEntities1 db = new testEntities1()) { var listEF = db.team; } } }
Test look like:
The result are very similar. Try to add join to our query.
Simple.Data join:
public class SimpleDataClass { public static void GetTableBySD() { string ConnectionString = @"Data Source = PAWEL; Initial Catalog = test; Integrated Security = True"; dynamic defaultDb = Database.OpenConnection(ConnectionString); var listFilter = defaultDb.team.All() .Select(defaultDb.players.Surname) .Join(defaultDb.players).On(defaultDb.players.ID_team == defaultDb.team.ID); foreach (var item in listFilter) { Console.WriteLine(item.Surname); } } }
ORM join:
public class ORM { public static void GetTableByORM() { using (testEntities1 db = new testEntities1()) { var listFilter2 = from a in db.team join b in db.players on a.ID equals b.ID_team select b.Surname; foreach (var item in listFilter2) { Console.WriteLine(item); } } } }
Result:
Here we have five records and time is five times bigger.
Insert
Let’s see the diffrence in the insert.
Simple.Data
public class SimpleDataClass { public static void GetTableBySD() { string ConnectionString = @"Data Source = PAWEL; Initial Catalog = test; Integrated Security = True"; dynamic defaultDb = Database.OpenConnection(ConnectionString); defaultDb.team.Insert(TeamName: "Real", League: "PD"); } }
ORM
public class ORM { public static void GetTableByORM() { using (testEntities1 db = new testEntities1()) { team _insert = new team(); _insert.TeamName = "Barca"; _insert.League = "PD"; db.team.Add(_insert); db.SaveChanges(); } } }
Result
And again we see the difference in the times between Entity Framework and Simple.Data.
Summary
Writing code in a simple.data looks more intuitive and is faster then EF. But the cost of this it is the lack of intellisense because we operate on dynamic variable. Any syntax errors are detected only after run applications. Plus is the simplicity of the writing unit test and perform faster then those that are based on eg. entity framework. A unit test example with Simple.Data.
If you are interested in library simple.data here is documentation.
Addition
Lazy loading vs eager loading vs simple data
I added a loop to measure time with eager loading.
var listFilter2 = (from b in db.players.Include(x => x.team) select b.Surname).ToList();
If you have lazy loading enabled in EF (by default s fast as I remember), then I guess your join comparison may be flawed. Have you tried to use .Include() method to say what tables should be eager-loaded? This may affect Entity Framework performance results. Also, how does Simple.Data handle transactions? It may be interesting to try to insert many entities within the same transaction. The performance comparison result may say a bit more about usage of these libraries in more real use cases.
1.I agree that I should use .AsNoTracking(), but just in case only if I want to display data, otherwise if I want to edit this data later it is recommended to use the default query, mean without .AsNoTracking().
2.I wrote a post that shows how generated is sql in eager loading and lazy loading here, and if someone want to see how generated is sql in simple.data this is written in the documentation here
In part with the addition I added loop and I removed the effect of “cold code” also I added eager loading, lazy loading to list().