{"id":58131,"date":"2021-06-14T08:00:21","date_gmt":"2021-06-14T06:00:21","guid":{"rendered":"https:\/\/code-maze.com\/?p=58131"},"modified":"2024-01-31T15:17:01","modified_gmt":"2024-01-31T14:17:01","slug":"using-dapper-with-asp-net-core-web-api","status":"publish","type":"post","link":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/","title":{"rendered":"Using Dapper with ASP.NET Core Web API"},"content":{"rendered":"<p>In this article, we&#8217;ll learn how to use Dapper in the ASP.NET Core Web API project. We&#8217;ll talk about Dapper overall, how to use different queries and executions, how to execute stored procedures, and how to create multiple queries inside a transaction. We&#8217;ll also create a simple repository layer to wrap the logic up to avoid using Dapper queries directly inside the controller.<\/p>\n<hr \/>\r\n<p style=\"text-align: center;\"><strong>VIDEO<\/strong>: Using Dapper with ASP.NET Core Web API.<\/p>\r\n<p style=\"text-align: center;\"><iframe width=\"560\" height=\"315\" src=https:\/\/www.youtube.com\/embed\/C763K-VGkfc frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\r\n<hr \/>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for this article, you can visit the <a href=\"https:\/\/github.com\/CodeMazeBlog\/dapper-aspnetcore-webapi\" target=\"_blank\" rel=\"nofollow noopener\">Dapper with ASP.NET Core Web API<\/a> repository.<\/div>\n<p>So, let&#8217;s start.<\/p>\n<h2 id=\"about-dapper\">About Dapper<\/h2>\n<p>Dapper is an ORM (Object-Relational Mapper) or, more precisely, a Micro ORM, which we can use to communicate with the database in our projects. We can write SQL statements using Dapper as we would in the SQL Server. Dapper performs well because it doesn&#8217;t translate queries we write in .NET to SQL. It is important to know that Dapper is SQL Injection safe because we can use parameterized queries, which we should always do. One more important thing is that Dapper supports multiple database providers. It extends ADO.NET&#8217;s IDbConnection and provides useful extension methods to query our database. Of course, we have to write queries compatible with our database provider.<\/p>\n<p>When discussing these extension methods, we must say that Dapper supports synchronous and asynchronous method executions. We&#8217;ll use the asynchronous version of those methods.<\/p>\n<h3>About Extension Methods<\/h3>\n<p>Dapper extends the IDbConnection interface with these multiple methods:<\/p>\n<ul>\n<li><strong>Execute<\/strong> &#8211; an extension method that we use to execute a command one or multiple times and return the number of affected rows<\/li>\n<li><strong>Query<\/strong> &#8211; with this extension method, we can execute a query and map the result<\/li>\n<li><strong>QueryFirst\u00a0<\/strong>&#8211; \u00a0it executes a query and maps the first result<\/li>\n<li><strong>QueryFirstOrDefault\u00a0<\/strong>&#8211; we use this method to execute a query and map the first result or a default value if the sequence contains no elements<\/li>\n<li><strong>QuerySingle <\/strong>&#8211;\u00a0an extension method that executes a query and maps the result.\u00a0 It throws an exception if there is not exactly one element in the sequence<\/li>\n<li><strong>QuerySingleOrDefault\u00a0<\/strong>&#8211; executes a query and maps the result or a default value if the sequence is empty. It throws an exception if there is more than one element in the sequence<\/li>\n<li><strong>QueryMultiple <\/strong>&#8211; an extension method that executes multiple queries within the same command and maps results<\/li>\n<\/ul>\n<p>As we said, Dapper provides an async version for all these methods (ExecuteAsync, QueryAsync, QueryFirstAsync, QueryFirstOrDefaultAsync, QuerySingleAsync, QuerySingleOrDefaultAsync, QueryMultipleAsync).<\/p>\n<h2 id=\"database-api-creation\">Database and Web API Creation and Dapper Installation<\/h2>\n<p>Before using Dapper in our project, we must prepare a database and create a new Web API project. So, let&#8217;s start with the database.<\/p>\n<p>The first thing we&#8217;ll do is create a new <code>ASPNetCoreDapper<\/code> database. After the database creation, you can navigate to our <a href=\"https:\/\/github.com\/CodeMazeBlog\/dapper-aspnetcore-webapi\" target=\"_blank\" rel=\"nofollow noopener\">source code repository<\/a><span style=\"color: #ff0000;\">\u00a0<\/span>and find a script (Initial Script with Data.sql) <span style=\"color: #ff0000;\"><span style=\"color: #000000;\">that you can execute to create two tables and populate them with data:<\/span><\/span><\/p>\n<p><span style=\"color: #ff0000;\"><span style=\"color: #000000;\"><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/01-Dapper-database-with-tables.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58132\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/01-Dapper-database-with-tables.png\" alt=\"Dapper database with tables\" width=\"163\" height=\"231\" \/><\/a>\u00a0<\/span><\/span><\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">If you want to learn how to create migrations and seed data with Dapper, you can read our <a href=\"https:\/\/code-maze.com\/dapper-migrations-fluentmigrator-aspnetcore\/\" target=\"_blank\" rel=\"noopener\">Dapper Migrations with FluentMigrator and ASP.NET Core<\/a> article.<\/div>\n<p>Once we have our table and the data, we can create a new Web API project.<\/p>\n<p>With our project in place, we can install two required packages:<\/p>\n<ul>\n<li>Dapper &#8211; <code>PM&gt; Install-Package Dapper<\/code><\/li>\n<li>SQL Client &#8211; <code>PM&gt; Install-Package Microsoft.Data.SqlClient<\/code><\/li>\n<\/ul>\n<p>Excellent.<\/p>\n<p>We can continue towards the Repository Pattern creation.<\/p>\n<h2 id=\"repository\">Creating Repository Pattern<\/h2>\n<p>In this section, we are going to create a simple repository pattern. We&#8217;ll make it simple because this article is about Dapper.<\/p>\n<div style=\"padding: 20px; border-left: 5px gray solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">If you want to learn how to create a <a href=\"https:\/\/code-maze.com\/net-core-web-development-part4\/\" target=\"_blank\" rel=\"noopener\">fully-fledged Repository Pattern<\/a>, you can read our article on that topic. Also, you can find <a href=\"https:\/\/code-maze.com\/async-generic-repository-pattern\/\" target=\"_blank\" rel=\"noopener\">the async version of it<\/a>\u00a0if you want to write it that way.<\/div>\n<p>That said, let&#8217;s start by creating a new <code>Entities<\/code> folder with two classes inside:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class Employee\r\n{\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n    public int Age { get; set; }\r\n    public string Position { get; set; }\r\n    public int CompanyId { get; set; }\r\n}<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class Company\r\n{\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n    public string Address { get; set; }\r\n    public string Country { get; set; }\r\n\r\n    public List&lt;Employee&gt; Employees { get; set; } = new List&lt;Employee&gt;();\r\n}<\/pre>\n<p>So, these are our two model classes representing our tables in the database.<\/p>\n<p>After this, we can modify the <code>appsettings.json<\/code> file by adding our connection string inside:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">\"ConnectionStrings\": {\r\n    \"SqlConnection\": \"server=.; database=DapperASPNetCore; Integrated Security=true\"\r\n  },<\/pre>\n<p>Of course, feel free to modify the connection string to fit your needs.<\/p>\n<p><strong>Also, since the Microsoft.Data.SqlClient package<\/strong> <strong>version 4<\/strong>, if your database is not using encryption, any connection will fail by default. So, you might get an error with your first request:\u00a0<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">A connection was successfully established with the server, but then an error occurred during the login process.\r\n(provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)<\/pre>\n<p>To avoid this, you have to modify your connection string:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">SqlConnection\": \"server=.; database=Dapper; Integrated Security=true; Encrypt=false\"<\/code><\/p>\n<p>This will prevent the error.<\/p>\n<p>Now, we are going to create a new <code>Context<\/code> folder and a new <code>DapperContext<\/code> class under it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class DapperContext\r\n{\r\n    private readonly IConfiguration _configuration;\r\n    private readonly string _connectionString;\r\n\r\n    public DapperContext(IConfiguration configuration)\r\n    {\r\n        _configuration = configuration;\r\n        _connectionString = _configuration.GetConnectionString(\"SqlConnection\");\r\n    }\r\n\r\n    public IDbConnection CreateConnection()\r\n        =&gt; new SqlConnection(_connectionString);\r\n}<\/pre>\n<p>We inject the <code>IConfiguration<\/code> interface to enable access to the connection string from our <code>appsettings.json<\/code> file. Also, we create the <code>CreateConnection<\/code> method, which returns a new <code>SQLConnection<\/code> object.\u00a0<\/p>\n<p>For this to work, we have to add several using statements:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using Microsoft.Data.SqlClient;\r\nusing Microsoft.Extensions.Configuration;\r\nusing System.Data;<\/pre>\n<p>After the class creation, we can register it as a singleton service in the <code>Startup<\/code> class, if you are using .NET5:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"3\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddSingleton&lt;DapperContext&gt;();\r\n    services.AddControllers();\r\n}<\/pre>\n<p><strong>In .NET 6 and above, we can do the registration in the Program class:<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"1\">builder.Services.AddSingleton&lt;DapperContext&gt;(); \r\nbuilder.Services.AddControllers();<\/pre>\n<h3>Repository Interfaces and Classes<\/h3>\n<p>Next, we are going to create a new <code>Contracts<\/code> folder and a single interface inside it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public interface ICompanyRepository\r\n{\r\n}<\/pre>\n<p>Also, let&#8217;s create a new <code>Repository<\/code> folder, and a single class inside it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CompanyRepository : ICompanyRepository\r\n{\r\n    private readonly DapperContext _context;\r\n\r\n    public CompanyRepository(DapperContext context)\r\n    {\r\n        _context = context;\r\n    }\r\n}<\/pre>\n<p>Once we start working with Dapper queries, we&#8217;ll populate both files.<\/p>\n<p>Finally, let&#8217;s register our interface and its implementation as a service in the <code>Startup<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"4\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddSingleton&lt;DapperContext&gt;();\r\n    services.AddScoped&lt;ICompanyRepository, CompanyRepository&gt;();\r\n    services.AddControllers();\r\n}<\/pre>\n<p><strong>Of course, for .NET 6, the registration is slightly different:<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"2\">builder.Services.AddSingleton&lt;DapperContext&gt;(); \r\nbuilder.Services.AddScoped&lt;ICompanyRepository, CompanyRepository&gt;(); \r\nbuilder.Services.AddControllers();<\/pre>\n<p>That&#8217;s it.\u00a0<\/p>\n<p>We can move on to our first query.<\/p>\n<h2 id=\"dapper-queries\">Using Dapper Queries in ASP.NET Core Web API<\/h2>\n<p>Let&#8217;s start with an example of returning all the companies from our database.<\/p>\n<p>So, the first thing we want to do is to modify our <code>ICompanyRepository<\/code> interface:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n}<\/pre>\n<p>Then, let&#8217;s implement this method in the <code>CompanyRepository<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies()\r\n{\r\n    var query = \"SELECT * FROM Companies\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var companies = await connection.QueryAsync&lt;Company&gt;(query);\r\n        return companies.ToList();\r\n    }\r\n}<\/pre>\n<p>So, we create a <code>query<\/code> string variable where we store our SQL query to fetch all the companies. Then inside the <code>using<\/code> statement, we use our <code>DapperContext<\/code> object to create the <code>SQLConnection<\/code> object (or, to be more precise an <code>IDbConnection<\/code> object) by calling the <code>CreateConnection()<\/code> method. As you can see, as soon as we stop using our connection, we must dispose of it. Once we create a connection, we can use it to call the <code>QueryAsync<\/code> method and pass the query as an argument. Since the <code>QueryAsync()<\/code> method returns <code>IEnumerable&lt;T&gt;<\/code>, we convert it to a list as soon as we want to return a result.<\/p>\n<p>It is important to notice that we use a strongly typed result from the <code>QueryAsync()<\/code> method: <code>QueryAsync&lt;Company&gt;(query)<\/code>. But Dapper supports anonymous results as well: <code>connection.QueryAsync(query)<\/code>. We are going to use the strongly typed results in our examples.<\/p>\n<h3>API Controller Logic<\/h3>\n<p>Now, let&#8217;s create a new <code>CompaniesController<\/code> and modify it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Route(\"api\/companies\")]\r\n[ApiController]\r\npublic class CompaniesController : ControllerBase\r\n{\r\n    private readonly ICompanyRepository _companyRepo;\r\n\r\n    public CompaniesController(ICompanyRepository companyRepo)\r\n    {\r\n        _companyRepo = companyRepo;\r\n    }\r\n\r\n    [HttpGet]\r\n    public async Task&lt;IActionResult&gt; GetCompanies()\r\n    {\r\n        try\r\n        {\r\n            var companies = await _companyRepo.GetCompanies();\r\n            return Ok(companies);\r\n        }\r\n        catch (Exception ex)\r\n        {\r\n            \/\/log error\r\n            return StatusCode(500, ex.Message);\r\n        }\r\n    }\r\n}<\/pre>\n<p>Here, we inject our repository via DI and use it to call our <code>GetCompanies<\/code> method.<\/p>\n<p>A few notes here. Since we don&#8217;t have any business logic, we are not creating a service layer to wrap our repository layer. For this type of application, the service layer would call repository methods and nothing more, adding an unnecessary level of complexity to the article. Of course, we always recommend using the service layer in larger-scale applications.<\/p>\n<p>We&#8217;ll use try-catch blocks in each action in our controller for the example&#8217;s sake. But to avoid code repetition, we strongly suggest reading our <a href=\"https:\/\/code-maze.com\/global-error-handling-aspnetcore\/\" target=\"_blank\" rel=\"noopener\">Global Error Handling<\/a> article.<\/p>\n<p>We&#8217;ll not explain a controller&#8217;s logic; we assume you are familiar with Web API development. If you want to learn more about that, you can read our <a href=\"https:\/\/code-maze.com\/net-core-series\/\" target=\"_blank\" rel=\"noopener\">ASP.NET Core Web API<\/a> series<\/p>\n<p>Now, we can start our app and test it:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/03-Postman-Result-For-First-Dapper-Query.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58135\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/03-Postman-Result-For-First-Dapper-Query.png\" alt=\"Postman Result For First Dapper Query\" width=\"674\" height=\"571\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/03-Postman-Result-For-First-Dapper-Query.png 674w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/03-Postman-Result-For-First-Dapper-Query-300x254.png 300w\" sizes=\"auto, (max-width: 674px) 100vw, 674px\" \/><\/a><\/p>\n<p>Excellent.<\/p>\n<p>We can see both our companies as a result.<\/p>\n<h2 id=\"different-property-column-names\">Different Property and Column Names<\/h2>\n<p>Right now, all the properties from the <code>Company<\/code> class have the same names as the columns inside the <code>Companies<\/code> table. But what would happen if those don&#8217;t match?<\/p>\n<p>Let&#8217;s check it out.<\/p>\n<p>First, we are going to modify the <code>Name<\/code> property inside the <code>Company<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"4\">public class Company\r\n{\r\n    public int Id { get; set; }\r\n    public string CompanyName { get; set; }\r\n    public string Address { get; set; }\r\n    public string Country { get; set; }\r\n\r\n    public List&lt;Employee&gt; Employees { get; set; } = new List&lt;Employee&gt;();\r\n}<\/pre>\n<p>Now, if we run the same request, we are going to get a different result:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/04-Wrong-mappings-between-Model-and-Column-name.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58137\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/04-Wrong-mappings-between-Model-and-Column-name.png\" alt=\"Wrong mappings between Model and Column name\" width=\"680\" height=\"576\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/04-Wrong-mappings-between-Model-and-Column-name.png 680w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/04-Wrong-mappings-between-Model-and-Column-name-300x254.png 300w\" sizes=\"auto, (max-width: 680px) 100vw, 680px\" \/><\/a><\/p>\n<p>As we can see, the <code>companyName<\/code> property is null. This is because Dapper can&#8217;t map it.<\/p>\n<p>So, let&#8217;s modify the query inside the <code>GetCompanies<\/code> method by using aliases:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"3\">public async Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies()\r\n{\r\n    var query = \"SELECT Id, Name AS CompanyName, Address, Country FROM Companies\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var companies = await connection.QueryAsync&lt;Company&gt;(query);\r\n        return companies.ToList();\r\n    }\r\n}<\/pre>\n<p>As you can see, we are using the <code>AS<\/code> keyword to create an alias for the <code>Name<\/code> column.<\/p>\n<p>Now, we can send the same request from Postman:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/05-Correct-mapping-with-Dapper-using-aliases.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58138\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/05-Correct-mapping-with-Dapper-using-aliases.png\" alt=\"Correct mapping with Dapper using aliases\" width=\"530\" height=\"461\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/05-Correct-mapping-with-Dapper-using-aliases.png 530w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/05-Correct-mapping-with-Dapper-using-aliases-300x261.png 300w\" sizes=\"auto, (max-width: 530px) 100vw, 530px\" \/><\/a><\/p>\n<p>We can see the mapping works perfectly.<\/p>\n<p>Let&#8217;s return everything to a previous state to avoid writing aliases in future queries.<\/p>\n<h2 id=\"parameters\">Using Parameters With Dapper Queries<\/h2>\n<p>As we said at the beginning of this article, Dapper supports parameterized queries, making it 100% SQL injection-safe. It supports anonymous, dynamic, list, string, and table-valued parameters. We are mostly going to use dynamic and anonymous parameters in this article.<\/p>\n<p>That said, let&#8217;s start with the interface modification:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"4\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n    public Task&lt;Company&gt; GetCompany(int id);\r\n}<\/pre>\n<p>Then, let&#8217;s add a method implementation in the <code>CompanyRepository<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;Company&gt; GetCompany(int id)\r\n{\r\n    var query = \"SELECT * FROM Companies WHERE Id = @Id\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var company = await connection.QuerySingleOrDefaultAsync&lt;Company&gt;(query, new { id });\r\n\r\n        return company;\r\n    }\r\n}<\/pre>\n<p>This method is almost the same as the previous one, but with one exception because we are using the <code>QuerySingleOrDefaultAsync<\/code> method here and provide an anonymous object as the second argument. We&#8217;ll show you how to use dynamic parameters in the next example, where we&#8217;ll create a new Company entity in our database.<\/p>\n<p>Next, we have to modify our controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet(\"{id}\", Name = \"CompanyById\")]\r\npublic async Task&lt;IActionResult&gt; GetCompany(int id)\r\n{\r\n    try\r\n    {\r\n        var company = await _companyRepo.GetCompany(id);\r\n        if (company == null)\r\n            return NotFound();\r\n\r\n        return Ok(company);\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>That&#8217;s it.<\/p>\n<p>We can test this with Postman:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/06-Parameterized-query-result.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58139\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/06-Parameterized-query-result.png\" alt=\"Parameterized query result\" width=\"674\" height=\"369\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/06-Parameterized-query-result.png 674w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/06-Parameterized-query-result-300x164.png 300w\" sizes=\"auto, (max-width: 674px) 100vw, 674px\" \/><\/a><\/p>\n<p>Excellent. It works like a charm.<\/p>\n<div style=\"padding: 20px; border-left: 5px gray solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">Also, if you want to read how to pass output parameters to stored procedures, you can do that in our <a href=\"https:\/\/code-maze.com\/csharp-pass-output-parameters-to-stored-procedures-dapper\/\" target=\"_blank\" rel=\"noopener\">Passing Output Parameters to Stored Procedures<\/a> article.<\/div>\n<h2 id=\"adding-new-entity\">Adding a New Entity in the Database with the Execute(Async) Method<\/h2>\n<p>Now, we are going to handle a POST request in our API and use the <code>ExecuteAsync<\/code> method to create a new company entity in the database.<\/p>\n<p>The first thing we are going to do is to create a new <code>Dto<\/code> folder, and inside it, a new <code>CompanyForCreationDto<\/code> class that we are going to use for the POST request:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CompanyForCreationDto\r\n{\r\n    public string Name { get; set; }\r\n    public string Address { get; set; }\r\n    public string Country { get; set; }\r\n}<\/pre>\n<p>If you want to learn more about why we use this DTO (and we are going to use another one for the Update action), you can read our <a href=\"https:\/\/code-maze.com\/net-core-series\/\" target=\"_blank\" rel=\"noopener\">ASP.NET Core Web API series<\/a> of articles, where we explain the reason behind this (articles <a href=\"https:\/\/code-maze.com\/net-core-web-development-part5\/\" target=\"_blank\" rel=\"noopener\">5<\/a> and <a href=\"https:\/\/code-maze.com\/net-core-web-development-part6\/\" target=\"_blank\" rel=\"noopener\">6<\/a> from the series).<\/p>\n<p>After creating this class, we are going to modify our interface:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n    public Task&lt;Company&gt; GetCompany(int id);\r\n    public Task CreateCompany(CompanyForCreationDto company);\r\n}<\/pre>\n<p>And, of course, let&#8217;s implement this method in the repository class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task CreateCompany(CompanyForCreationDto company)\r\n{\r\n    var query = \"INSERT INTO Companies (Name, Address, Country) VALUES (@Name, @Address, @Country)\";\r\n\r\n    var parameters = new DynamicParameters();\r\n    parameters.Add(\"Name\", company.Name, DbType.String);\r\n    parameters.Add(\"Address\", company.Address, DbType.String);\r\n    parameters.Add(\"Country\", company.Country, DbType.String);\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        await connection.ExecuteAsync(query, parameters);\r\n    }\r\n}<\/pre>\n<p>Here, we create our query and a dynamic parameters object (we are not using an anonymous object anymore). We populate that object with our three parameters and then call the <code>ExecuteAsync<\/code> method to execute our insert statement. The <code>ExecuteAsync<\/code> method returns <code>int<\/code> as a result, representing the number of affected rows in the database. So, if you need that information, you can use it by accepting the return value from this method.<\/p>\n<p>Now, if we call this method and pass a company for creation to it, it will create a new entity for us. But, while creating API&#8217;s POST action, it is a good practice to return a link, which the API&#8217;s users can use to navigate to the created entity. Our <a href=\"https:\/\/code-maze.com\/ultimate-aspnetcore-webapi-second-edition\/?source=content\">Ultimate ASP.NET Core Web API book<\/a> explains this in great detail. We can&#8217;t easily do that with the code, as we have it in this method. So, we have to modify a couple of things.<\/p>\n<h3>Creating a Better API Solution<\/h3>\n<p>Firstly, let&#8217;s modify the interface:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n    public Task&lt;Company&gt; GetCompany(int id);\r\n    public Task&lt;Company&gt; CreateCompany(CompanyForCreationDto company);\r\n}<\/pre>\n<p>This time, we want our method to return a created company entity.<\/p>\n<p>Next, we have to modify the method implementation:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"1,3-4,13-23\">public async Task&lt;Company&gt; CreateCompany(CompanyForCreationDto company)\r\n{\r\n    var query = \"INSERT INTO Companies (Name, Address, Country) VALUES (@Name, @Address, @Country)\" +\r\n        \"SELECT CAST(SCOPE_IDENTITY() as int)\";\r\n\r\n    var parameters = new DynamicParameters();\r\n    parameters.Add(\"Name\", company.Name, DbType.String);\r\n    parameters.Add(\"Address\", company.Address, DbType.String);\r\n    parameters.Add(\"Country\", company.Country, DbType.String);\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var id = await connection.QuerySingleAsync&lt;int&gt;(query, parameters);\r\n\r\n        var createdCompany = new Company\r\n        {\r\n            Id = id,\r\n            Name = company.Name,\r\n            Address = company.Address,\r\n            Country = company.Country\r\n        };\r\n\r\n        return createdCompany;\r\n    }\r\n}<\/pre>\n<p>We modify our query by adding another <code>SELECT<\/code> statement, which returns the last identity value created in the current scope. Then, we extract that id value by calling the <code>QuerySingleAsync()<\/code> method. This method executes both <code>INSERT<\/code> and <code>SELECT<\/code> statements. Once we have the Id value, we create a new company object with the required fields. Of course, you can do this with any mapping tool you like. Finally, we return our created entity.<\/p>\n<p>With this out of the way, we can add a POST action in our controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPost]\r\npublic async Task&lt;IActionResult&gt; CreateCompany(CompanyForCreationDto company)\r\n{\r\n    try\r\n    {\r\n        var createdCompany = await _companyRepo.CreateCompany(company);\r\n        return CreatedAtRoute(\"CompanyById\", new { id = createdCompany.Id }, createdCompany);\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>As you can see, after creating a new company in the database, we return a route to fetch our newly created entity.<\/p>\n<p>Let&#8217;s test it:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/07-Created-Company-Result.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58143\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/07-Created-Company-Result.png\" alt=\"Created Company Result\" width=\"673\" height=\"584\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/07-Created-Company-Result.png 673w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/07-Created-Company-Result-300x260.png 300w\" sizes=\"auto, (max-width: 673px) 100vw, 673px\" \/><\/a><\/p>\n<p>There is our new company.<\/p>\n<p>Also, if we inspect the Headers tab of the response, we are going to find a URI for this company:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/08-URI-for-a-new-company-as-a-response-to-a-POST-request.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58144\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/08-URI-for-a-new-company-as-a-response-to-a-POST-request.png\" alt=\"URI for a new company as a response to a POST request\" width=\"959\" height=\"281\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/08-URI-for-a-new-company-as-a-response-to-a-POST-request.png 959w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/08-URI-for-a-new-company-as-a-response-to-a-POST-request-300x88.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/08-URI-for-a-new-company-as-a-response-to-a-POST-request-768x225.png 768w\" sizes=\"auto, (max-width: 959px) 100vw, 959px\" \/><\/a><\/p>\n<p>Awesome.<\/p>\n<p>Let&#8217;s move on.<\/p>\n<h2 id=\"update-delete\">Working with Update and Delete<\/h2>\n<p>Working with the update and delete is pretty simple because we already have all the required knowledge. So, let&#8217;s jump straight to the code.<\/p>\n<p>We are going to start with a new DTO:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CompanyForUpdateDto\r\n{\r\n    public string Name { get; set; }\r\n    public string Address { get; set; }\r\n    public string Country { get; set; }\r\n}<\/pre>\n<p>Then, let&#8217;s modify the interface:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"6-7\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n    public Task&lt;Company&gt; GetCompany(int id);\r\n    public Task&lt;Company&gt; CreateCompany(CompanyForCreationDto company);\r\n    public Task UpdateCompany(int id, CompanyForUpdateDto company);\r\n    public Task DeleteCompany(int id);\r\n}<\/pre>\n<p>Next, we have to implement these two methods in a repository class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task UpdateCompany(int id, CompanyForUpdateDto company)\r\n{\r\n    var query = \"UPDATE Companies SET Name = @Name, Address = @Address, Country = @Country WHERE Id = @Id\";\r\n\r\n    var parameters = new DynamicParameters();\r\n    parameters.Add(\"Id\", id, DbType.Int32);\r\n    parameters.Add(\"Name\", company.Name, DbType.String);\r\n    parameters.Add(\"Address\", company.Address, DbType.String);\r\n    parameters.Add(\"Country\", company.Country, DbType.String);\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        await connection.ExecuteAsync(query, parameters);\r\n    }\r\n}\r\n\r\npublic async Task DeleteCompany(int id)\r\n{\r\n    var query = \"DELETE FROM Companies WHERE Id = @Id\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        await connection.ExecuteAsync(query, new { id });\r\n    }\r\n}<\/pre>\n<p>As you can see, there is nothing new with these two methods. We have a query and parameters, and we execute our statements with the <code>ExecuteAsync<\/code> method.<\/p>\n<p>Finally, we have to add two actions to the controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPut(\"{id}\")]\r\npublic async Task&lt;IActionResult&gt; UpdateCompany(int id, CompanyForUpdateDto company)\r\n{\r\n    try\r\n    {\r\n        var dbCompany = await _companyRepo.GetCompany(id);\r\n        if (dbCompany == null)\r\n            return NotFound();\r\n\r\n        await _companyRepo.UpdateCompany(id, company);\r\n        return NoContent();\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}\r\n\r\n[HttpDelete(\"{id}\")]\r\npublic async Task&lt;IActionResult&gt; DeleteCompany(int id)\r\n{\r\n    try\r\n    {\r\n        var dbCompany = await _companyRepo.GetCompany(id);\r\n        if (dbCompany == null)\r\n            return NotFound();\r\n\r\n        await _companyRepo.DeleteCompany(id);\r\n        return NoContent();\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>That&#8217;s it.\u00a0<\/p>\n<p>We can test this with Postman by sending both PUT and DELETE requests:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/09-Update-Request-with-Dapper.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58146\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/09-Update-Request-with-Dapper.png\" alt=\"Update Request with Dapper\" width=\"692\" height=\"439\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/09-Update-Request-with-Dapper.png 692w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/09-Update-Request-with-Dapper-300x190.png 300w\" sizes=\"auto, (max-width: 692px) 100vw, 692px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/10-Delete-Request-with-Dapper.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58147\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/10-Delete-Request-with-Dapper.png\" alt=\"Delete Request with Dapper\" width=\"711\" height=\"441\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/10-Delete-Request-with-Dapper.png 711w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/10-Delete-Request-with-Dapper-300x186.png 300w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/a><\/p>\n<p>Great job.<\/p>\n<h2 id=\"stored-procedures\">Running Stored Procedures with Dapper<\/h2>\n<p>Before we show you how to use Dapper to call a stored procedure, we have to create one in our database:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">USE [DapperASPNetCore]\r\nGO\r\n\r\nSET ANSI_NULLS ON\r\nGO\r\n\r\nSET QUOTED_IDENTIFIER ON\r\nGO\r\n\r\nCREATE PROCEDURE [dbo].[ShowCompanyForProvidedEmployeeId] @Id int\r\nAS\r\nSELECT c.Id, c.Name, c.Address, c.Country\r\nFROM Companies c JOIN Employees e ON c.Id = e.CompanyId\r\nWhere e.Id = @Id\r\n\r\nGO<\/pre>\n<p>This procedure returns a company&#8217;s Name, Address, and Country with an employee with a provided Id value.<\/p>\n<p>With the stored procedure in place, we can move on to the interface modification:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"8\">public interface ICompanyRepository\r\n{\r\n    public Task&lt;IEnumerable&lt;Company&gt;&gt; GetCompanies();\r\n    public Task&lt;Company&gt; GetCompany(int id);\r\n    public Task&lt;Company&gt; CreateCompany(CompanyForCreationDto company);\r\n    public Task UpdateCompany(int id, CompanyForUpdateDto company);\r\n    public Task DeleteCompany(int id);\r\n    public Task&lt;Company&gt; GetCompanyByEmployeeId(int id);\r\n}<\/pre>\n<p>Then, let&#8217;s modify the class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;Company&gt; GetCompanyByEmployeeId(int id)\r\n{\r\n    var procedureName = \"ShowCompanyForProvidedEmployeeId\";\r\n    var parameters = new DynamicParameters();\r\n    parameters.Add(\"Id\", id, DbType.Int32, ParameterDirection.Input);\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var company = await connection.QueryFirstOrDefaultAsync&lt;Company&gt;\r\n            (procedureName, parameters, commandType: CommandType.StoredProcedure);\r\n\r\n        return company;\r\n    }\r\n}<\/pre>\n<p>Here, we create a variable that contains a procedure name and a dynamic parameter object with a single parameter inside. Because our stored procedure returns a value, we use the <code>QueryFirstOrDefaultAsync<\/code> method to execute it. Pay attention that if your stored procedure doesn&#8217;t return a value, you can use the <code>ExecuteAsync<\/code> method for execution.<\/p>\n<p>As usual, we have to add another action in our controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet(\"ByEmployeeId\/{id}\")]\r\npublic async Task&lt;IActionResult&gt; GetCompanyForEmployee(int id)\r\n{\r\n    try\r\n    {\r\n        var company = await _companyRepo.GetCompanyByEmployeeId(id);\r\n        if (company == null)\r\n            return NotFound();\r\n\r\n        return Ok(company);\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>And, of course, the test:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/11-Company-by-Employee-Id-executing-stored-procedure-with-Dapper.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58148\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/11-Company-by-Employee-Id-executing-stored-procedure-with-Dapper.png\" alt=\"Company by Employee Id - executing stored procedure with Dapper\" width=\"675\" height=\"367\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/11-Company-by-Employee-Id-executing-stored-procedure-with-Dapper.png 675w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/11-Company-by-Employee-Id-executing-stored-procedure-with-Dapper-300x163.png 300w\" sizes=\"auto, (max-width: 675px) 100vw, 675px\" \/><\/a><\/p>\n<p>We can see how easy it is to call a stored procedure with Dapper in our project.<\/p>\n<h2 id=\"multiple-sql-statements\">Executing Multiple SQL Statements with a Single Query<\/h2>\n<p>Using the <code>QueryMultipleAsync()<\/code> method, we can easily execute multiple SQL statements and return multiple results in a single query.\u00a0<\/p>\n<p>Let&#8217;s see how to do that with an example.<\/p>\n<p>As always, we&#8217;ll modify our interface first:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public interface ICompanyRepository\r\n{\r\n    ...\r\n    public Task&lt;Company&gt; GetCompanyEmployeesMultipleResults(int id);\r\n}<\/pre>\n<p>Then the implementation:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;Company&gt; GetCompanyEmployeesMultipleResults(int id)\r\n{\r\n    var query = \"SELECT * FROM Companies WHERE Id = @Id;\" +\r\n                \"SELECT * FROM Employees WHERE CompanyId = @Id\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    using (var multi = await connection.QueryMultipleAsync(query, new { id }))\r\n    {\r\n        var company = await multi.ReadSingleOrDefaultAsync&lt;Company&gt;();\r\n        if (company != null)\r\n            company.Employees = (await multi.ReadAsync&lt;Employee&gt;()).ToList();\r\n\r\n        return company;\r\n    }\r\n}<\/pre>\n<p>As you can see, our query variable contains two <code>SELECT<\/code> statements. The first will return a single company, and the second one will return all the employees of that company. After that, we create a connection and then use that connection to call the <code>QueryMultipleAsync<\/code> method. Once we get multiple results inside the <code>multi<\/code> variable, we can extract both results (company and employees per that company) by using the <code>ReadSignleOrDefaultAsync<\/code> and <code>ReadAsync<\/code> methods. The first method returns a single result, while the second returns a collection.<\/p>\n<p>All we have to do is to create an action in the controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet(\"{id}\/MultipleResult\")]\r\npublic async Task&lt;IActionResult&gt; GetCompanyEmployeesMultipleResult(int id)\r\n{\r\n    try\r\n    {\r\n        var company = await _companyRepo.GetCompanyEmployeesMultipleResults(id);\r\n        if (company == null)\r\n            return NotFound();\r\n\r\n        return Ok(company);\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>And let&#8217;s test it:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/12-Fetching-multiple-results-in-a-single-query.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58150\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/12-Fetching-multiple-results-in-a-single-query.png\" alt=\"Fetching multiple results in a single query\" width=\"677\" height=\"708\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/12-Fetching-multiple-results-in-a-single-query.png 677w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/12-Fetching-multiple-results-in-a-single-query-287x300.png 287w\" sizes=\"auto, (max-width: 677px) 100vw, 677px\" \/><\/a><\/p>\n<p>There we go. We can see all the employees attached for a single company.<\/p>\n<h2 id=\"multiple-mapping\">Multiple Mapping<\/h2>\n<p>In a previous example, we used two SQL statements to return two results and then join them together in a single object. But usually, for such queries, we don&#8217;t want to write two SQL statements. We want to use a JOIN clause and create a single SQL statement. Of course, if we write it like that, we can&#8217;t use the <code>QueryMultipleAsync()<\/code> method anymore. We have to use a multiple mapping technique with a well-known <code>QueryAsync()<\/code> method.<\/p>\n<p>So, let&#8217;s see how we can do it.<\/p>\n<p>As usual, we are going to start with the interface modification:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"4\">public interface ICompanyRepository\r\n{\r\n    ...\r\n    public Task&lt;List&lt;Company&gt;&gt; GetCompaniesEmployeesMultipleMapping();\r\n}<\/pre>\n<p>Next, the implementation:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;List&lt;Company&gt;&gt; GetCompaniesEmployeesMultipleMapping()\r\n{\r\n    var query = \"SELECT * FROM Companies c JOIN Employees e ON c.Id = e.CompanyId\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        var companyDict = new Dictionary&lt;int, Company&gt;();\r\n\r\n        var companies = await connection.QueryAsync&lt;Company, Employee, Company&gt;(\r\n            query, (company, employee) =&gt;\r\n            {\r\n                if (!companyDict.TryGetValue(company.Id, out var currentCompany))\r\n                {\r\n                    currentCompany = company;\r\n                    companyDict.Add(currentCompany.Id, currentCompany);\r\n                }\r\n\r\n                currentCompany.Employees.Add(employee);\r\n                return currentCompany;\r\n            }\r\n        );\r\n\r\n        return companies.Distinct().ToList();\r\n    }\r\n}<\/pre>\n<p>So, we create a query, and inside the using statement, a new connection. Then, we create a new dictionary to keep our companies in. To extract data from the database, we are using the <code>QueryAsync()<\/code> method, but it has a new syntax we haven&#8217;t seen this time. We can see three generic types. The first two are the input types we&#8217;ll work with, and the third is the return type. This method accepts our query as a parameter and a <code>Func<\/code> delegate that accepts two parameters of type <code>Company<\/code> end <code>Employee<\/code>. Inside the delegate, we try to extract a company by its Id value. If it doesn&#8217;t exist, we store it inside the <code>currentCompany<\/code> variable and add it to the dictionary. Also, we assign all the employees to that current company and return it from a <code>Func<\/code> delegate.<\/p>\n<p>After mapping, we return a distinct result converted to a list.<\/p>\n<p>All we have left to do is to add an action to the controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet(\"MultipleMapping\")]\r\npublic async Task&lt;IActionResult&gt; GetCompaniesEmployeesMultipleMapping()\r\n{\r\n    try\r\n    {\r\n        var company = await _companyRepo.GetCompaniesEmployeesMultipleMapping();\r\n\r\n        return Ok(company);\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        \/\/log error\r\n        return StatusCode(500, ex.Message);\r\n    }\r\n}<\/pre>\n<p>That should be it.<\/p>\n<p>Let&#8217;s test it:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/13-Dapper-multiple-mapping.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-58161\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/13-Dapper-multiple-mapping.png\" alt=\"Dapper multiple mapping\" width=\"685\" height=\"734\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/13-Dapper-multiple-mapping.png 685w, https:\/\/code-maze.com\/wp-content\/uploads\/2021\/05\/13-Dapper-multiple-mapping-280x300.png 280w\" sizes=\"auto, (max-width: 685px) 100vw, 685px\" \/><\/a><\/p>\n<p>And we can see it works like a charm.<\/p>\n<div style=\"padding: 20px; border-left: 5px gray solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\"><strong>One important note: <\/strong>If you like the article so far, then maybe it can help even more for you to know that we updated our <a href=\"https:\/\/code-maze.com\/ultimate-aspnetcore-webapi-second-edition\/\" target=\"_blank\" rel=\"noopener\">Web API Premium edition<\/a> with another bonus book called <strong>ASP.NET Core with Dapper<\/strong>. In this book, you can read more about these topics: migrations with dapper, paging, searching, filtering, and sorting, and also about authorization with ASP.NET Core Identity.<\/div>\n<p>We have one more thing left to cover &#8211; transactions.<\/p>\n<h2 id=\"transactions\">Transactions<\/h2>\n<p>Transactions are pretty simple to use with Dapper. We can execute it using the Dapper library (the one we already use) or the <a href=\"https:\/\/www.nuget.org\/packages\/Dapper.Transaction\/\" target=\"_blank\" rel=\"nofollow noopener\">Dappr.Transaction<\/a> library, which is the same thing as Dapper, just with the extended <code>IDbConnection<\/code> interface. In our example, we are going to use the Dapper library.<\/p>\n<p>We&#8217;ll show you just the repository method where we implement transactions. All the rest is pretty simple as we repeated the steps several times in this article:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task CreateMultipleCompanies(List&lt;CompanyForCreationDto&gt; companies)\r\n{\r\n    var query = \"INSERT INTO Companies (Name, Address, Country) VALUES (@Name, @Address, @Country)\";\r\n\r\n    using (var connection = _context.CreateConnection())\r\n    {\r\n        connection.Open();\r\n\r\n        using (var transaction = connection.BeginTransaction())\r\n        {\r\n            foreach (var company in companies)\r\n            {\r\n                var parameters = new DynamicParameters();\r\n                parameters.Add(\"Name\", company.Name, DbType.String);\r\n                parameters.Add(\"Address\", company.Address, DbType.String);\r\n                parameters.Add(\"Country\", company.Country, DbType.String);\r\n\r\n                await connection.ExecuteAsync(query, parameters, transaction: transaction);\r\n            }\r\n\r\n            transaction.Commit();\r\n        }\r\n    }\r\n}<\/pre>\n<p>So, there are four additional things here we haven&#8217;t seen so far. First, we have to open the connection. Then, inside the <code>using<\/code> statement, we start our transactions by calling the <code>BeginTransaction()<\/code> method. In the <code>ExecuteAsync()<\/code> method, we specify our transaction. And finally, we call the <code>Commit<\/code> method to commit the transaction.<\/p>\n<p>If you want to simulate an error and test that no rows will be created in the database, you can throw an exception below the <code>await<\/code> code line. You will find no new rows in the Companies table.<\/p>\n<h2>Conclusion<\/h2>\n<p>There we go.<\/p>\n<p>We&#8217;ve learned how to integrate Dapper into the ASP.NET Core project and how to use queries, executions, stored procedures, and transactions with Dapper.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we&#8217;ll learn how to use Dapper in the ASP.NET Core Web API project. We&#8217;ll talk about Dapper overall, how to use different queries and executions, how to execute stored procedures, and how to create multiple queries inside a transaction. We&#8217;ll also create a simple repository layer to wrap the logic up to [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":58346,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[1647,2079],"tags":[79,889,893,890,892,522,891,50,130],"class_list":["post-58131","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dapper","category-web-api","tag-asp-net-core","tag-dapper","tag-dapper-transaction","tag-execute","tag-executeasync","tag-query","tag-queryfirstordefaultasync","tag-repository-pattern","tag-web-api","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Using Dapper with ASP.NET Core Web API - Code Maze<\/title>\n<meta name=\"description\" content=\"Let&#039;s learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Dapper with ASP.NET Core Web API - Code Maze\" \/>\n<meta property=\"og:description\" content=\"Let&#039;s learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2021-06-14T06:00:21+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-31T14:17:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Marinko Spasojevi\u0107\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marinko Spasojevi\u0107\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\"},\"author\":{\"name\":\"Marinko Spasojevi\u0107\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\"},\"headline\":\"Using Dapper with ASP.NET Core Web API\",\"datePublished\":\"2021-06-14T06:00:21+00:00\",\"dateModified\":\"2024-01-31T14:17:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\"},\"wordCount\":3020,\"commentCount\":77,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png\",\"keywords\":[\"asp.net core\",\"Dapper\",\"Dapper Transaction\",\"Execute\",\"ExecuteAsync\",\"Query\",\"QueryFirstOrDefaultAsync\",\"repository pattern\",\"Web API\"],\"articleSection\":[\"Dapper\",\"Web API\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\",\"url\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\",\"name\":\"Using Dapper with ASP.NET Core Web API - Code Maze\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png\",\"datePublished\":\"2021-06-14T06:00:21+00:00\",\"dateModified\":\"2024-01-31T14:17:01+00:00\",\"description\":\"Let's learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png\",\"width\":1100,\"height\":620,\"caption\":\"Using Dapper with ASP.NET Core Web API\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Dapper with ASP.NET Core Web API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\",\"name\":\"Marinko Spasojevi\u0107\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"caption\":\"Marinko Spasojevi\u0107\"},\"description\":\"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/marinko\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using Dapper with ASP.NET Core Web API - Code Maze","description":"Let's learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/","og_locale":"en_US","og_type":"article","og_title":"Using Dapper with ASP.NET Core Web API - Code Maze","og_description":"Let's learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.","og_url":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/","og_site_name":"Code Maze","article_published_time":"2021-06-14T06:00:21+00:00","article_modified_time":"2024-01-31T14:17:01+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png","type":"image\/png"}],"author":"Marinko Spasojevi\u0107","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Marinko Spasojevi\u0107","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/"},"author":{"name":"Marinko Spasojevi\u0107","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533"},"headline":"Using Dapper with ASP.NET Core Web API","datePublished":"2021-06-14T06:00:21+00:00","dateModified":"2024-01-31T14:17:01+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/"},"wordCount":3020,"commentCount":77,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png","keywords":["asp.net core","Dapper","Dapper Transaction","Execute","ExecuteAsync","Query","QueryFirstOrDefaultAsync","repository pattern","Web API"],"articleSection":["Dapper","Web API"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/","url":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/","name":"Using Dapper with ASP.NET Core Web API - Code Maze","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png","datePublished":"2021-06-14T06:00:21+00:00","dateModified":"2024-01-31T14:17:01+00:00","description":"Let's learn how to use Dapper in ASP.NET Core Web API by using different querys, executions, transactions and repository pattern.","breadcrumb":{"@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/06\/Using-Dapper-with-ASP.NET-Core-Web-API.png","width":1100,"height":620,"caption":"Using Dapper with ASP.NET Core Web API"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/using-dapper-with-asp-net-core-web-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Using Dapper with ASP.NET Core Web API"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533","name":"Marinko Spasojevi\u0107","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","caption":"Marinko Spasojevi\u0107"},"description":"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.","sameAs":["https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/marinko\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/58131","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=58131"}],"version-history":[{"count":25,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/58131\/revisions"}],"predecessor-version":[{"id":103706,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/58131\/revisions\/103706"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/58346"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=58131"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=58131"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=58131"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}