Thứ Hai, 8 tháng 8, 2016

Dapper vs Entity Framework vs ADO.NET Performance Benchmarking


https://www.exceptionnotfound.net/dapper-vs-entity-framework-vs-ado-net-performance-benchmarking/
We have an upcoming project in my group that is going to need to be very, very performant. This project will involve us querying for data from a SQL database, transforming that data into strongly-typed objects, then returning those objects to the calling system through a service layer. Eventually, this service will be a central pillar in our organization's service-oriented architecture (SOA), and as such it absolutely has to be fast.
We generally want to use Entity Framework for our ORM, but just a little searching revealsStackExchange questions and blog post after blog post detailing how EF is simply not up to par for high-performance systems. Into that gap steps so-called "micro-ORMs" likeDapper.NET (which is used on the StackExchange family of sites including StackOverflow) which promise performance at the cost of maintainability. As always, we also have the option of using straight ADO.NET queries.
Thing is, because performance needs to be front-and-center in this app, I'd like to be really sure which of these ORMs provide the best bang for my buck. So I worked up a sample project over on GitHub that takes each of these three data access methods and beats them till they beg for mercy tests them using the same sample data and same queries (with some caveats, as we'll see below). This post is divided up into the following sections:

Methodology

This test uses a database schema that looks like this:
A database diagram, showing that a Sport has many Teams, and a Team has many Players.
In other words, a Sport has many Teams, and a Team has many Players.
I needed some sample data to test against. The sample project has an entire sectiondedicated to producing this data, but suffice to say that you can select how many sports, how many teams per sport, and how many players per team you want for each test.
Now what I needed was a set of queries that I could create in each ORM and test against. I chose three different queries:
  • Player by ID
  • Players per Team
  • Teams per Sport (including Players)
For each Query, I will run the test against all data in the database (e.g. for Player by ID I will select each player by their ID) and average the total time it takes to execute the query (including setting up the DbContext or SqlConnection, as the case may be) for each execution. Then, I will do multiple runs of this over the same data so that I can average them out and get a set of numbers that should clearly show which of the ORMs is the fastest.

Test Setup

As an example, here's the code for the Entity Framework, ADO.NET, and Dapper.NET test classes test class:
public class EntityFramework : ITestSignature  
{
    public long GetPlayerByID(int id)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SportContext context = new SportContext())
        {
            var player = context.Players.Where(x => x.Id == id).First();
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetPlayersForTeam(int teamId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SportContext context = new SportContext())
        {
            var players = context.Players.Where(x => x.TeamId == teamId).ToList();
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetTeamsForSport(int sportId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SportContext context = new SportContext())
        {
            var players = context.Teams.Include(x=>x.Players).Where(x => x.SportId == sportId).ToList();
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }
}
public class ADONET : ITestSignature  
{
    public long GetPlayerByID(int id)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using(SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            using(SqlDataAdapter adapter = new SqlDataAdapter("SELECT Id, FirstName, LastName, DateOfBirth, TeamId FROM Player WHERE Id = @ID", conn))
            {
                adapter.SelectCommand.Parameters.Add(new SqlParameter("@ID", id));
                DataTable table = new DataTable();
                adapter.Fill(table);
            }
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetPlayersForTeam(int teamId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using(SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            using(SqlDataAdapter adapter = new SqlDataAdapter("SELECT Id, FirstName, LastName, DateOfBirth, TeamId FROM Player WHERE TeamId = @ID", conn))
            {
                adapter.SelectCommand.Parameters.Add(new SqlParameter("@ID", teamId));
                DataTable table = new DataTable();
                adapter.Fill(table);
            }
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetTeamsForSport(int sportId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using(SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            using(SqlDataAdapter adapter = new SqlDataAdapter("SELECT p.Id, p.FirstName, p.LastName, p.DateOfBirth, p.TeamId, t.Id as TeamId, t.Name, t.SportId FROM Player p INNER JOIN Team t ON p.TeamId = t.Id WHERE t.SportId = @ID", conn))
            {
                adapter.SelectCommand.Parameters.Add(new SqlParameter("@ID", sportId));
                DataTable table = new DataTable();
                adapter.Fill(table);
            }
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }
}
public class Dapper : ITestSignature  
{
    public long GetPlayerByID(int id)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            var player = conn.Query<PlayerDTO>("SELECT Id, FirstName, LastName, DateOfBirth, TeamId FROM Player WHERE Id = @ID", new{ ID = id});
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetPlayersForTeam(int teamId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            var players = conn.Query<List<PlayerDTO>>("SELECT Id, FirstName, LastName, DateOfBirth, TeamId FROM Player WHERE TeamId = @ID", new { ID = teamId });
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }

    public long GetTeamsForSport(int sportId)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        using (SqlConnection conn = new SqlConnection(Constants.ConnectionString))
        {
            conn.Open();
            var players = conn.Query<PlayerDTO, TeamDTO, PlayerDTO>("SELECT p.Id, p.FirstName, p.LastName, p.DateOfBirth, p.TeamId, t.Id as TeamId, t.Name, t.SportId FROM Team t "
                + "INNER JOIN Player p ON t.Id = p.TeamId WHERE t.SportId = @ID", (player, team) => { return player; }, splitOn: "TeamId", param: new { ID = sportId });
        }
        watch.Stop();
        return watch.ElapsedMilliseconds;
    }
}
Note that in Dapper.NET and ADO.NET's cases, we will be selecting a row for each Player in the GetTeamsForSport query. This is not an exact comparison against the EF query, but for my purposes it works fine.

Results

The following results are for 10 iterations, each containing 8 sports, 30 teams in each sport, and 100 players per team.

Entity Framework Results

RunPlayer by IDPlayers for TeamTeams for Sport
11.64ms4.57ms127.75ms
20.56ms3.47ms112.5ms
30.17ms3.27ms119.12ms
41.01ms3.27ms106.75ms
51.15ms3.47ms107.25ms
61.14ms3.27ms117.25ms
70.67ms3.27ms107.25ms
80.55ms3.27ms110.62ms
90.37ms4.4ms109.62ms
100.44ms3.43ms116.25ms
Average0.77ms3.57ms113.45ms

ADO.NET Results

RunPlayer by IDPlayers for TeamTeams for Sport
10.01ms1.03ms10.25ms
20ms1ms11ms
30.1ms1.03ms9.5ms
40ms1ms9.62ms
50ms1.07ms7.62ms
60.02ms1ms7.75ms
70ms1ms7.62ms
80ms1ms8.12ms
90ms1ms8ms
100ms1.17ms8.88ms
Average0.013ms1.03ms8.84ms

Dapper.NET Results

RunPlayer by IDPlayers for TeamTeams for Sport
10.38ms1.03ms9.12ms
20.03ms1ms8ms
30.02ms1ms7.88ms
40ms1ms8.12ms
50ms1.07ms7.62ms
60.02ms1ms7.75ms
70ms1ms7.62ms
80ms1.02ms7.62ms
90ms1ms7.88ms
100.02ms1ms7.75ms
Average0.047ms1.01ms7.94ms

Analysis

As we can see in the data above Entity Framework is markedly slower than either ADO.NET or Dapper.NET, on the order of 3-10 times slower.
Let's be clear: the methodology used in this test had something to do with this, particularly the "Teams per Sport" query. In that query, Entity Framework was selecting both the teams in a given sport and the players involved with each team (via an Include() statement), whereas the ADO.NET and Dapper.NET queries were just selecting joined data. In a more rigorous statistical study, the test would either be improved or these results would be thrown out.
What's more interesting to me is that Dapper.NET was, on average, faster than ADO.NET for the more complex queries. It appears to me that there is a performance hit the first time you use Dapper.NET (as also appears to happen with EF) but once you get past that, Dapper.NET is amazingly fast. I suspect that this has something to do with the fact that in the ADO.NET test cases we are using a SqlDataAdapter, though I cannot prove this.
Even if you do throw out the "Teams per Sport" query, you're still left with EF being at least 3 times slower than either Dapper.NET or ADO.NET. The data shows that, at least in terms of raw speed and with these queries, Entity Framework will be the slowest option, and Dapper.NET will (narrowly) be the fastest. Which is why my ultimate conclusion might surprise you.

Conclusion

We're going to use Dapper.NET on our project; that much is not in doubt. However, we're not going to start development with it, and it will not be the only ORM in use. The plan is to develop this project using Entity Framework, and later optimize to use Dapper.NET in certain scenarios where the system needs a performance boost. Yes, we are going with the slowest option to start. Why would we do this?
Because the major drawback to using Dapper.NET is that you have naked SQL queries in your code. If anybody fat-fingers anything, we won't be aware of any issues until we run the tests against the code. Plus, the members of my group are more familiar with EF than Dapper.NET, and therefore development time will be quicker.
In short, Dapper.NET is unquestionably faster than EF and slightly faster than straight ADO.NET, but we'll be doing the majority of development in EF and then optimizing with Dapper.NET where needed. We think this will strike a balance between ease of development and performance (and hopefully allow us to both get it done and do it right).
Don't believe me? Good! Go get the app and see for yourself!
(Also, if you see anything obviously wrong in my methodology, tell me about it! I'd be happy to update this post and the sample project if problems are found in it.)
Happy Coding!

Using HTTP Methods (GET, POST, PUT, etc.) in Web API

Using HTTP Methods (GET, POST, PUT, etc.) in Web API

My group has been studying ASP.NET Web API for a major project we're working on, and part of learning about this tech stack is studying how HTTP works, which has been a nice refresher for us. A couple of my teammates asked me to clarify the HTTP Methods (e.g. GET, POST, PUT, DELETE, etc) we were going to use for specific actions, and I wanted to learn more about them. Hence, this post. Come along with us as we learn about HTTP methods (also calledverbs) and discuss how and when to use them in our Web API projects!

What Are HTTP Methods?

Whenever a client submits a request to a server, part of that request is an HTTP method, which is what the client would like the server to do with the specified resource. HTTP methodsrepresent those requested actions. For example, some commonly-used HTTP methods will retrieve data from a server, submit data to a server for processing, delete an item from the server's data store, etc. For a more general overview of HTTP, see Tutorials Point's article.

Selecting The Appropriate Method

A large portion of application functionality can be summed up in the acronym CRUD, which stands for Create, Read, Update, Delete. There are four HTTP methods that correspond to these actions, one for each, like so:
C - Create - POST
R - Read - GET
U - Update - PUT
D - Delete - DELETE
So, in a given app, you might have the following action:
public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}
We can tell from the name of the action (and, let's be real, the comment) that this action is supposed to create a movie. So we should use the POST verb on this action, like so:
[HttpPost]
public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}
If you need a particular action to support more than one HTTP method, you can use the [AcceptVerbs] attribute:
[AcceptVerbs("POST", "PUT")]
public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}
For the majority of applications, GET, POST, PUT, and DELETE should be all the HTTP methods you need to use. However, there are a few other methods we could utilize if the need arises.
  • HEAD: This is identical to a GET request, but only returns the headers for the response, not the response body. Theoretically faster, commonly used for checking to see if a particular resources exists or can be accessed.
  • OPTIONS: Returns the HTTP methods supported by the server for the specified URL.
  • PATCH: Submits a partial modification to a resource. If you only need to update one field for the resource, you may want to use the PATCH method.

POST vs PUT

POST and PUT are very similar in that they both send data to the server that the server will need to store somewhere. Technically speaking, you could use either for the Create or Update scenarios, and in fact this is rather common. The difference lies in the details.
PUT is idempotent. What this means is that if you make the same request twice using PUT, with the same parameters both times, the second request will have no effect. This is why PUT is generally used for the Update scenario; calling Update more than once with the same parameters doesn't do anything more than the first call did.
By contrast, POST is not idempotent; making the same call using POST with same parameters each time will cause two different things to happen, hence why POST is commonly used for the Create scenario (submitting two identical items to a Create method should create two entries in the data store).
(It should be noted that, strictly speaking, HTTP does not force PUT to be idempotent, so you can implement your server to use PUT in a non-idempotent way. However, doing so is liable to cause a horde of angry server admins to show up at your desk and beat you with ethernet cables. Don't say I didn't warn you.)

Default HTTP Methods

If we do not assign an explicit HTTP method to a controller action, what method(s) does that action accept? Let's imagine we have a Web API controller like so:
public class MovieController : ApiController  
{
    /// <summary>
    /// Returns all movies.
    /// </summary>
    /// <returns>A JSON list of all movies.</returns>
    [Route("movies/all")]
    public IHttpActionResult All()
    {
        List<Movie> movies = new List<Movie>()
        {
            new Movie()
            {
                Id = 1,
                Title = "Up",
                ReleaseDate = new DateTime(2009,5,29),
                RunningTimeMinutes = 96
            },
            new Movie()
            {
                Id = 2,
                Title = "Toy Story",
                ReleaseDate = new DateTime(1995, 11, 19),
                RunningTimeMinutes = 81
            },
            new Movie()
            {
                Id = 3,
                Title = "Big Hero 6",
                ReleaseDate = new DateTime(2014, 11, 7),
                RunningTimeMinutes = 102
            }
        };

        return Ok(movies);
    }
}
We can tell by looking at the code that this should be a GET action, since it is returning data. However, we're not explicitly saying that GET should be used (there's no [HttpGet] attribute). So, what method(s) will this action accept? Let's see what Postman can tell us.
It should be a GET action, so let's try to hit this action with a GET request.
Well, that didn't work, we get back a 405 Method Not Allowed status. Why were we not able to use the GET method?
The algorithm ASP.NET uses to calculate the "default" method for a given action goes like this:
  1. If there is an attribute applied (via [HttpGet][HttpPost][HttpPut][AcceptVerbs], etc), the action will accept the specified HTTP method(s).
  2. If the name of the controller action starts the words "Get", "Post", "Put", "Delete", "Patch", "Options", or "Head", use the corresponding HTTP method.
  3. Otherwise, the action supports the POST method.
We're falling in to the #3 condition here: the action name All() doesn't contain any of the key words and we didn't specify an action, so this action will only support POST. Sure enough, guess what Postman shows for a POST action?
Obviously, this is not what we want. We're getting data from the server using a POST method, and this (while not technologically prevented) is not what these HTTP methods were designed for.
We could solve this problem in two ways. The first would be to add the [HttpGet] attribute to the method. The second would be to rename the method to GetAll(); the existence of the word "Get" at the start of the method tells ASP.NET to accept a GET HTTP method on this action. My personal preference is to always explicitly state which HTTP method is accepted by any action, like so:
public class MovieController : ApiController  
{
    /// <summary>
    /// Returns all movies.
    /// </summary>
    /// <returns>A JSON list of all movies.</returns>
    [Route("movies/all")]
    [HttpGet] //Always explicitly state the accepted HTTP method
    public IHttpActionResult All()
    {
        //Get movies
        return Ok(movies);
    }
}

Summary

Always use the appropriate HTTP action in your Web API actions, as it establishes the kinds of communication your consumers can conduct with your app. Further, always explicitly state what HTTP method(s) each action can accept, and keep to the common definitions for each action (e.g. GET for data retrieval, POST for creating data, PUT for updating data, etc.).
For more information, check out ASP.NET Web API 2: Building a Restful Service from Start to Finish by Jamie Kurtz, specifically Chapter 2, "What is RESTful?" and Chapter 5, "Up and Down the Stack with a POST".
Happy Coding!

http://www.bravohex.com/2014/03/adonet-entity-framework-tim-hieu-khai.html

http://www.bravohex.com/2014/03/adonet-entity-framework-tim-hieu-khai.html
Trong bài này, chúng ta tìm hiểu những khái niệm khái quát, giản đơn để bạn có thể nắm rõ Entity Framework nhanh chóng nếu bạn là người mới.

  • EF với version đầu tiên đi kèm với .NET 3.5 trong bộ Visual Studio 2008, phát hành 11/2008. Ở lần đầu ra mắt này, nó nhận được đánh giá không mấy tốt đẹp của các nhà phát triển.
  • Version tiếp theo là EF4.0 phát hành cùng .NET 4.0 vào 12/04/2010. Cập nhật một số hạn chế ở phiên bản đầu tiên.
  • Version thứ 3 của EF là version 4.1,phát hành vào 12/04/2011. Lần phát hành này có dấu ấn quan trọng là hỗ trợ Code First (Sử dụng code để làm việc với EF không dùng Tools) 
  • Cứ thế các phiên bản khác ra đời v4.1, v4.3.1,v5.0,v6.0 và bây giờ là version 6.1
  • Tham khảo thêm tại: Wikipedia

 Entity Framework Dùng Làm Gì ?

- Chúng ta dùng EF để truy xuất dữ liệu (Accessing Data).
Trước đó để truy xuất dữ liệu các nhà phát triển thường sử dụng:Raw Data, Driect APIs,OLEDB, ODBC, Embedded SQL, ADO, Stored Procedure, ADO.NET, Datasets, DataReader, LINQ Và bây giờ với EF là O/RM
- Mục đích che dấu sự phức tạp bên dưới và đưa ra cách làm việc thống nhất, hiện đại, nhanh gọn. 


Lợi Ích Sử Dụng Entity Framework ?

- Năng suất làm việc được đẩy nhanh hơn
- Giữ tính độc lập cho cơ sở dữ liệu
(Điều đó không có nghĩa EF là giải pháp duy nhất tốt trong các vấn đề cũng như nó không phải là nhanh nhất trong công việc. Trong một số trường hợp bạn cần có các thiết lập bổ sung )
- Cho phép làm việc với nhiều hệ quản trị cơ sở dữ liệu SQL Server, MySQL, DB, Oracle .... 


Vậy Entity Framework Là Gì ?

- Entity Framework là O/RM  (Object Relational Mapping )  trong .NET Framwork . Có thể nói là tốt nhất trong việc truy xuất dữ liệu trên .NET 
- Là công nghệ  Microsoft thường được sử dụng trong : WCF Data services, Azure Table Storage, Sharepoint 2010, SQL Server Reporting Services and PowerPivot for Excel, …
- EF là công nghệ cho phép bạn làm việc với CSDL quan hệ. 

Một Số Khái Niệm Cần Lưu Ý Khi Làm Việc Với Entity Framework

Entity Data Model

Được phát minh bởi TS. Peter Chen năm  1970 và được đặt tên là ERM (Entity Relationship Model).
Sau này trong Entity FrameWork được gọi là EDM (Entity Data Model
- Conceptual model: (Phần mở rộng *.CSDL) là các các class model và các relationships của chúng. Nó độc lập với thiết kế Table trong cơ sở dữ liệu của bạn.
- Mapping: (Phần mở rộng *.MSL) nó bao gồm các thông tin về Conceptual model ánh xạ lên Storage model.
- Storage model: (Phần mở rộng *.SSDL) là mô hình thiết kế cơ sở dữ liệu của bạn nó bao gồm các Tables, Views, Stored Procedures, Relationships, Keys 

Object Relation Mapping

- Thứ nhất ORM là một công cụ được áp dụng trong Entity Framework 
- ORM sử dụng thông tin Metadata để giao tiếp với cơ sở dữ liệu. Nhờ vậy, bạn không cần biết cấu trúc bên dưới của cơ sở dữ liệu. ORM là công cụ trung gian để che dấu đi sự phức tạp đó cho bạn.
- Nó là cơ chế anh xạ nên phần quan trọng nhất của ORM chính là mapping. Hiểu đơn giản ORM là trung gian cho việc ánh xạ từ bản thiết kế EDM xuống Database

Quy Trình Làm Việc Với Entity FrameWork ?


Tòm tắt lại, có ba cách làm việc với Entity Framework:
- Database First: Trong trường hợp bạn muốn làm việc với database đã có sẵn. Dùng công cụ thiết kế có sẵn trong Visual Studio để generated từ database ra bản thiết kế model. 
- Model First: Trong trường hợp này, chúng ta sẽ làm việc trên visual studio và tạo ra database mới tại đây. Dùng công cụ để generated code từ bản thiết kế model ra database
- Code First: Riêng với cách này bạn có 2 lựa chọn, làm việc với database có sẵn hoặc sẽ tạo mới. Nhưng dù làm với cách nào, chúng ta cũng dùng codebehind để xử lý là chính. Không dùng các tool, giao diện trực quan giống như 2 cách bên trên.

Từ 3 cách tiếp cận trên, ta có thể hình dung ra hai cách thức chung:

- Sử dụng giao diện trực quan.
  • Database First: Áp dụng cho trường hợp đã có sẵn database
  • Model First: Áp dụng cho trường hợp ta thiết kế model và dùng nó tạo ra database
- Sử dụng hoàn toàn bằng code:
  • Code First dùng trong trường hợp database có sẵn
  • Code First  dùng trong trường hợp cần tạo mới database chỉ bằng code behind
References:
[1] http://www.entityframeworktutorial.net/EntityFramework-Architecture.aspx
[2] http://entityframework.codeplex.com/
[3] http://msdn.microsoft.com/en-us/library/bb399567%28v=vs.110%29.aspx

Update: 16/03/2014 
Update: 27/03/2014