<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blogs.repodb.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blogs.repodb.net/" rel="alternate" type="text/html" /><updated>2026-07-16T18:31:50+00:00</updated><id>https://blogs.repodb.net/feed.xml</id><title type="html">REPODB BLOGS</title><subtitle>A hybrid ORM library for .NET.</subtitle><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><entry><title type="html">Complete support to Dynamics</title><link href="https://blogs.repodb.net/posts/2020/12/repodb-dynamic-complete-support" rel="alternate" type="text/html" title="Complete support to Dynamics" /><published>2020-12-30T00:00:00+00:00</published><updated>2020-12-30T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/12/repodb-dynamic-complete-support</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/12/repodb-dynamic-complete-support"><![CDATA[<p>Today, we are announcing the availability of <a href="https://www.nuget.org/packages/RepoDb/1.12.5">RepoDb v1.12.5</a> and its bundles, the extension libraries at &gt;= v1.1.2. See below.</p>

<ul>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqlServer/1.1.2">RepoDb.SqlServer v1.1.2</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqlServer.BulkOperations/1.1.2">RepoDb.SqlServer.BulkOperations v1.1.2</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqLite/1.1.2">RepoDb.SqLite v1.1.2</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.MySql/1.1.3">RepoDb.MySql v1.1.3</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.MySqlConnector/1.1.2">RepoDb.MySqlConnector v1.1.2</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.PostgreSql/1.1.2">RepoDb.PostgreSql v1.1.2</a></li>
</ul>

<h3 id="tldr">TL;DR;</h3>

<p>These releases come with the complete support for the DYNAMIC operations. It also comes with a lot of bug fixes and enhancements.</p>

<blockquote>
  <p>The major release feature is being called DYNAMICS as it is enabling the dynamic capabilities if we are to use it in the context of an ORM. Therefore, do not get confused comparing the terminology against the dynamics within the .NET ecosystem.</p>
</blockquote>

<h3 id="push-operations">Push Operations</h3>

<p>This release is now supporting the capability of pushing an instance of <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> or <a href="https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.idictionary-2?view=net-6.0">IDictionary&lt;string, object&gt;</a> object into the push operations mentioned below.</p>

<ul>
  <li><a href="/operation/insert">Insert</a></li>
  <li><a href="/operation/merge">Merge</a></li>
  <li><a href="/operation/update">Update</a></li>
</ul>

<p>And an instance of <code class="language-plaintext highlighter-rouge">IEnumerable&lt;ExpandoObject&gt;</code> or <code class="language-plaintext highlighter-rouge">IEnumerable&lt;IDictionary&lt;string, object&gt;&gt;</code> object into the push operations mentioned below.</p>

<ul>
  <li><a href="/operation/insertall">InsertAll</a></li>
  <li><a href="/operation/mergeall">MergeAll</a></li>
  <li><a href="/operation/updateall">UpdateAll</a></li>
  <li><a href="/operation/bulkdelete">BulkDelete</a></li>
  <li><a href="/operation/bulkinsert">BulkInsert</a></li>
  <li><a href="/operation/bulkmerge">BulkMerge</a></li>
  <li><a href="/operation/bulkupdate">BulkUpdate</a></li>
</ul>

<p>Though the use-case ratio percentage is low, in some cases (edge-cases), it is quite important to get enabled.</p>

<p>The main target is just to fully enable the support for dynamic capabilities in the context of an ORM.</p>

<h4 id="sample-scenarios">Sample Scenarios</h4>

<p>Let us say, you would like to copy the data from one table into another table that is residing in a different database, then the dynamic code snippet below would do the job for you.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">sourceConnection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="nf">QueryAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">);</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">destinationConnection</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">destinationConnection</span><span class="p">.</span><span class="nf">InsertAll</span><span class="p">(</span><span class="s">"[sales].[Customer]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
    <span class="p">}</span>   
<span class="p">}</span>
</code></pre></div></div>

<p>When you query all the people from the <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> table, it returns an instance of <code class="language-plaintext highlighter-rouge">IEnumerable&lt;ExpandoObject&gt;</code>. The <a href="/operation/insertall">InsertAll</a> is now capable of accepting such argument value.</p>

<p>If you think the data is quite big enough, you can instead use the <a href="/operation/bulkinsert">BulkInsert</a> operation like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">destinationConnection</span><span class="p">.</span><span class="nf">BulkInsert</span><span class="p">(</span><span class="s">"[sales].[Customer]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
</code></pre></div></div>

<p>Also, notice that you have not even created a single model to accomplish the job, for as long as the structure of the source table <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> is identical to the destination table <code class="language-plaintext highlighter-rouge">[sales].[Customer]</code>, then you can do insert and/or bulk-process it.</p>

<p>You can as well filter the results based on the target fields from the destination table like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">sourceConnection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">destinationConnection</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">DbFieldCache</span>
            <span class="p">.</span><span class="nf">Get</span><span class="p">(</span><span class="s">"[sales].[Customer]"</span><span class="p">,</span> <span class="n">destinationConnection</span><span class="p">,</span> <span class="n">transaction</span><span class="p">:</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="nf">AsField</span><span class="p">());</span>
        <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="nf">QueryAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">fields</span><span class="p">:</span> <span class="n">fields</span><span class="p">);</span>
        <span class="n">destinationConnection</span><span class="p">.</span><span class="nf">InsertAll</span><span class="p">(</span><span class="s">"[sales].[Customer]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
    <span class="p">}</span>   
<span class="p">}</span>
</code></pre></div></div>

<p>Or, just add your own literal string like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">sourceConnection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">destinationConnection</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">"SSN"</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="nf">QueryAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">fields</span><span class="p">:</span> <span class="n">fields</span><span class="p">);</span>
        <span class="n">destinationConnection</span><span class="p">.</span><span class="nf">InsertAll</span><span class="p">(</span><span class="s">"[sales].[Customer]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
    <span class="p">}</span>   
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>As the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> is also a dictionary object underneath, if the identity column is present in the destination table but is absent from the source list (i.e.: <code class="language-plaintext highlighter-rouge">IEnumerable&lt;ExpandoObject&gt;</code>, <code class="language-plaintext highlighter-rouge">IEnumerable&lt;IDictionary&lt;string, object&gt;&gt;</code>) during the operations (i.e.: <a href="/operation/insert">Insert</a>, <a href="/operation/insertall">InsertAll</a> and <a href="/operation/bulkinsert">BulkInsert</a>), then, the new key-value-pair (KVP) entry will be created in the underlying dictionary object. The same logic applies to the <a href="/operation/merge">Merge</a>, <a href="/operation/mergeall">MergeAll</a> and <a href="/operation/bulkmerge">BulkMerge</a> operations.</p>
</blockquote>

<h3 id="operations">Operations</h3>

<p>Below are the code snippets for each of the affected operations.</p>

<h4 id="insert">Insert</h4>

<p>Below is a sample code snippet for <a href="/operation/insert">Insert</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">"John Doe"</span> <span class="p">},</span>
        <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">"New York"</span> <span class="p">}</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>If the identity column is present on the <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> table, then a new entry of key-value-pair will be added to the <code class="language-plaintext highlighter-rouge">person</code> variable.</p>
</blockquote>

<h4 id="insertallbulkinsert">InsertAll/BulkInsert</h4>

<p>Let us say you have this method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="kt">int</span> <span class="n">count</span> <span class="p">=</span> <span class="m">10</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
        <span class="p">{</span>
            <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">$"Name </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s">"</span> <span class="p">},</span>
            <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">$"Address</span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s">"</span> <span class="p">}</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, below is a sample code snippet for <a href="/operation/insertall">InsertAll</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">100</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">insertedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">InsertAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And below is for <a href="/operation/bulkinsert">BulkInsert</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">10000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">insertedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkInsert</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>If the identity column is present on the <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> table, then the new entries of the key-value-pairs will be added to each item of the <code class="language-plaintext highlighter-rouge">people</code> variable.</p>
</blockquote>

<h4 id="merge">Merge</h4>

<p>Below is a sample code snippet for <a href="/operation/merge">Merge</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="p">{</span> <span class="s">"Id"</span><span class="p">,</span> <span class="m">10045</span> <span class="p">}</span>
        <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">"James Smith"</span> <span class="p">},</span>
        <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">"New York"</span> <span class="p">}</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Merge</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>If the identity column is present on the <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> table, then a new entry of key-value-pair will be added to the <code class="language-plaintext highlighter-rouge">person</code> variable.</p>
</blockquote>

<p>By default, the primary and/or identity column will be used as qualifier, but you can specify your custom qualifiers like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Merge</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<h4 id="mergeallbulkmerge">MergeAll/BulkMerge</h4>

<p>Let us say you have this method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="kt">int</span> <span class="n">count</span> <span class="p">=</span> <span class="m">10</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
        <span class="p">{</span>
            <span class="p">{</span> <span class="s">"Id"</span><span class="p">,</span> <span class="n">i</span> <span class="p">}</span>
            <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">$"Name </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s"> - Merged"</span> <span class="p">},</span>
            <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">$"Address</span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s"> - Merged"</span> <span class="p">}</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, below is a sample code snippet for <a href="/operation/mergeall">MergeAll</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">100</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">MergeAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And below is for <a href="/operation/bulkmerge">BulkMerge</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">10000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkMerge</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>If the identity column is present on the <code class="language-plaintext highlighter-rouge">[dbo].[Person]</code> table, then the new entries of the key-value-pairs will be added to each item of the <code class="language-plaintext highlighter-rouge">people</code> variable.</p>
</blockquote>

<p>By default, the primary and/or identity column will be used as qualifier, but you can specify your custom qualifiers like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// MergeAll</span>
<span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">MergeAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span>
    <span class="n">people</span><span class="p">,</span>
    <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>

<span class="c1">// BulkMerge</span>
<span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkMerge</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span>
    <span class="n">people</span><span class="p">,</span>
    <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<h4 id="update">Update</h4>

<p>Below is a sample code snippet for <a href="/operation/update">Update</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="p">{</span> <span class="s">"Id"</span><span class="p">,</span> <span class="m">10045</span> <span class="p">},</span>
        <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">"John Doe"</span> <span class="p">},</span>
        <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">"California"</span> <span class="p">},</span>
        <span class="p">{</span> <span class="s">"UpdatedUtc"</span><span class="p">,</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span> <span class="p">}</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">updatedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Update</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>By default, the primary and/or identity column will be used as qualifier, but you can specify your custom qualifiers like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">updatedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Update</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<h4 id="updateallbulkupdate">UpdateAll/BulkUpdate</h4>

<p>Let us say you have this method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="kt">int</span> <span class="n">count</span> <span class="p">=</span> <span class="m">10</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
        <span class="p">{</span>
            <span class="p">{</span> <span class="s">"Id"</span><span class="p">,</span> <span class="n">i</span> <span class="p">}</span>
            <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">$"Name </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s"> - Updated"</span> <span class="p">},</span>
            <span class="p">{</span> <span class="s">"Address"</span><span class="p">,</span> <span class="s">$"Address</span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s"> - Updated"</span> <span class="p">}</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, below is a sample code snippet for <a href="/operation/updateall">Updated</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">100</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">UpdateAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And below is for <a href="/operation/bulkupdate">BulkUpdate</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">10000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">updatedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkUpdate</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>By default, the primary and/or identity column will be used as qualifier, but you can specify your custom qualifiers like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// UpdateAll</span>
<span class="kt">var</span> <span class="n">updatedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">UpdateAll</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span>
    <span class="n">people</span><span class="p">,</span>
    <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>

<span class="c1">// BulkUpdate</span>
<span class="kt">var</span> <span class="n">updatedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkUpdate</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span>
    <span class="n">people</span><span class="p">,</span>
    <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<h4 id="bulkdelete">BulkDelete</h4>

<p>Let us say you have this method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="nf">GetKeys</span><span class="p">(</span><span class="kt">int</span> <span class="n">count</span> <span class="p">=</span> <span class="m">10</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span>
        <span class="p">{</span>
            <span class="p">{</span> <span class="s">"Id"</span><span class="p">,</span> <span class="n">i</span> <span class="p">},</span>
            <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">$"Name </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s">"</span> <span class="p">}</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And below is for <a href="/operation/bulkdelete">BulkDelete</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetPeople</span><span class="p">(</span><span class="m">10000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">deletedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkDelete</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>By default, the primary and/or identity column will be used as qualifier, but you can specify your custom qualifiers like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">deletedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkDelete</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<p>Or, you can also just bulk-delete through the list of primary keys.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">keys</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="m">10045</span><span class="p">,</span> <span class="p">...,</span> <span class="m">11211</span> <span class="p">};</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connection</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">deletedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkDelete</span><span class="p">(</span><span class="s">"[dbo].[Person]"</span><span class="p">,</span> <span class="n">primaryKeys</span><span class="p">:</span> <span class="n">keys</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="bug-fixes-and-enhancements">Bug Fixes and Enhancements</h3>

<ul>
  <li>Adhoc: Remove the Initialize method from the <a href="/class/dataentitydatareader">DataEntityDataReader</a>. <a href="https://github.com/mikependon/RepoDB/issues/673">#673</a> - this is a breaking change</li>
  <li>Bug: Query failed when field mapping used on FSharp records. <a href="https://github.com/mikependon/RepoDB/issues/662">#662</a></li>
  <li>Bug: <a href="/mapper/fluentmapper">FluentMapper</a> is not working with Abstract Properties <a href="https://github.com/mikependon/RepoDB/issues/666">#666</a></li>
  <li>Bug: <a href="/operation/bulkinsert">BulkInsert</a> with mappings <a href="https://github.com/mikependon/RepoDB/issues/668">#668</a></li>
  <li>Question: <a href="/interface/ipropertyhandler">IPropertyHandler</a> for <code class="language-plaintext highlighter-rouge">Dictionary&lt;string, string&gt;</code> <a href="https://github.com/mikependon/RepoDB/issues/647">#647</a></li>
  <li>Upgraded the <a href="https://learn.microsoft.com/en-us/sql/connect/ado-net/introduction-microsoft-data-sqlclient-namespace?view=sql-server-ver16">Microsoft.Data.SqlClient</a> to <code class="language-plaintext highlighter-rouge">v2.1.0</code>.</li>
  <li>Upgraded the <code class="language-plaintext highlighter-rouge">System.ComponentModel.Annotations</code> to <code class="language-plaintext highlighter-rouge">v5.0.0</code>.</li>
  <li>Request: Introduce optional caching to <a href="/operation/executescalar">ExecuteScalar</a> methods. <a href="https://github.com/mikependon/RepoDB/issues/648">#648</a></li>
  <li>Enhancement: Add the non-parameterized Truncate operation. <a href="https://github.com/mikependon/RepoDB/issues/652">#652</a></li>
  <li>Request: Do not crash on an empty enumerable during a bulk operation <a href="https://github.com/mikependon/RepoDB/issues/635">#635</a>.</li>
  <li>Bug: Exception is being thrown for the Type level <a href="/features/propertyhandlers">PropertyHandler</a> for Dynamic Insertion <a href="https://github.com/mikependon/RepoDB/issues/628">#628</a>.</li>
  <li>Added a validation to ensure the type of the <code class="language-plaintext highlighter-rouge">TPropertyHandler</code> has implemented the <a href="/interface/ipropertyhandler">IPropertyHandler</a> interface when calling the <code class="language-plaintext highlighter-rouge">Add()</code> method of the <a href="/cacher/propertyhandlercache">PropertyHandlerCache</a> object.</li>
  <li>Enhancement: Add the dynamic <a href="/operation/executequerymultiple">ExecuteQueryMultiple</a> method in the <a href="/class/dbrepository">DbRepository</a> <a href="https://github.com/mikependon/RepoDB/issues/630">#630</a></li>
  <li>Possible bug - Enum with Flag attribute is not correctly handled <a href="https://github.com/mikependon/RepoDB/issues/624">#624</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/insert">Insert</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/234">#234</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/merge">Merge</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/238">#238</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/update">Update</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/236">#236</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/insertall">InsertAll</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/235">#235</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/mergeall">MergeAll</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/239">#239</a></li>
  <li>[Core] Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/updateall">UpdateAll</a> via <code class="language-plaintext highlighter-rouge">TableName</code>. <a href="https://github.com/mikependon/RepoDB/issues/237">#237</a></li>
  <li>Introduce the support of Dynamic and ExpandoObject in <a href="/operation/bulkinsert">BulkInsert</a>. <a href="https://github.com/mikependon/RepoDB/issues/243">#243</a></li>
  <li>Enhancement: Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/bulkinsert">BulkInsert</a> <a href="https://github.com/mikependon/RepoDB/issues/610">#610</a></li>
  <li>Enhancement: Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/bulkmerge">BulkMerge</a> <a href="https://github.com/mikependon/RepoDB/issues/611">#611</a></li>
  <li>Enhancement: Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/bulkupdate">BulkUpdate</a> <a href="https://github.com/mikependon/RepoDB/issues/612">#612</a></li>
  <li>Enhancement: Support <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a> in <a href="/operation/bulkdelete">BulkDelete</a> <a href="https://github.com/mikependon/RepoDB/issues/613">#613</a></li>
  <li>Bug: BulkInsert with mappings <a href="https://github.com/mikependon/RepoDB/issues/668">#668</a></li>
  <li>Bug: System.Data.SqlClient.SqlException: ‘Column name ‘ID’ does not exist in the target table or view.’ <a href="https://github.com/mikependon/RepoDB/issues/651">#651</a></li>
  <li>Refactor the internal method implementations to only utilize the base methods for both the MDS and SDS method calls.</li>
  <li>Bug: Incorrect syntax near the keyword <code class="language-plaintext highlighter-rouge">WITH</code> <a href="/operation/bulkinsert">BulkMergeAsync</a> <a href="https://github.com/mikependon/RepoDB/issues/640">#640</a></li>
  <li>Request: Do not crash on an empty enumerable during a bulk operation <a href="https://github.com/mikependon/RepoDB/issues/635">#635</a></li>
</ul>

<h3 id="credits">Credits</h3>

<p>Thank you to our contributors and to all the collaborators.</p>

<h4 id="contributors">Contributors</h4>

<ul>
  <li><a href="https://github.com/fredliex">fredliex</a> - for issuing the following PRs
    <ul>
      <li><a href="https://github.com/mikependon/RepoDB/issues/657">#657</a> - fix <a href="https://github.com/mikependon/RepoDB/issues/650">#650</a> <code class="language-plaintext highlighter-rouge">TypeExtension.IsPlainType</code> seems to misjudge the string property</li>
      <li><a href="https://github.com/mikependon/RepoDB/issues/658">#658</a> - some unit test case assign culture en-US when convert <a href="https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=net-7.0">System.DateTime</a> to <a href="https://learn.microsoft.com/en-us/dotnet/api/system.string?view=net-7.0">string</a>.</li>
      <li><a href="https://github.com/mikependon/RepoDB/issues/680">#680</a> - fix convert error for type level with <code class="language-plaintext highlighter-rouge">propertyHandler</code>. 🚀 <strong>This is awesome!</strong></li>
    </ul>
  </li>
  <li><a href="https://github.com/SergerGood">SergerGood</a> - for issuing the following PRs. Btw, thanks for being a frequent PR contributor.
    <ul>
      <li><a href="https://github.com/mikependon/RepoDB/issues/625">#625</a> - Benchmarks for the UpdateAll methods</li>
      <li><a href="https://github.com/mikependon/RepoDB/issues/620">#620</a> - Benchmarks for the GetAll methods</li>
    </ul>
  </li>
  <li><a href="https://github.com/Swoorup">Swoorup</a> - for issuing a PR <a href="https://github.com/mikependon/RepoDB/issues/619">#619</a></li>
  <li><a href="https://github.com/SpaceOgre">SpaceOgre</a> - for issuing a PR <a href="https://github.com/mikependon/RepoDB/issues/678">#678</a></li>
  <li><a href="https://github.com/stefandevo">stefandevo</a> - for issuing a PR <a href="https://github.com/mikependon/RepoDB/issues/642">#642</a> - Bug: Incorrect syntax near the keyword ‘WITH’ BulkMergeAsync</li>
  <li><a href="https://github.com/bobduncan">bobduncan</a> - for issuing a PR <a href="https://github.com/mikependon/RepoDB/issues/649">#649</a> - <a href="https://github.com/mikependon/RepoDB/issues/645">#645</a> Correctly passed through tableName parameter in the DeleteAll</li>
</ul>

<h4 id="collaborators">Collaborators</h4>

<p>For our active collaborators on this release:</p>

<ul>
  <li><a href="https://github.com/Swoorup">Swoorup</a></li>
  <li><a href="https://github.com/fredliex">fredliex</a></li>
  <li><a href="https://github.com/SpaceOgre">SpaceOgre</a></li>
  <li><a href="https://github.com/kbilsted">kbilsted</a></li>
  <li><a href="https://github.com/Jmaharman">Jmaharman</a></li>
  <li><a href="https://github.com/nandaccio">nandaccio</a></li>
  <li><a href="https://github.com/stefandevo">stefandevo</a></li>
  <li><a href="https://github.com/bobduncan">bobduncan</a></li>
</ul>

<p>For the other collaborators of this release (filing the Issues/Bugs, Questions, Recommendations, Verification/Validations, etc)</p>

<ul>
  <li><a href="https://github.com/rledyard">rledyard</a></li>
  <li><a href="https://github.com/lucwuyts">lucwuyts</a></li>
  <li><a href="https://github.com/gkn06">gkn06</a></li>
  <li><a href="https://github.com/Olli64">Olli64</a></li>
  <li><a href="https://github.com/BieleckiLtd">BieleckiLtd</a></li>
  <li><a href="https://github.com/cwsterling">cwsterling</a></li>
  <li><a href="https://github.com/DmitryBatalov">DmitryBatalov</a></li>
</ul>

<p>Please continue to do so and</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[Today, we are announcing the availability of RepoDb v1.12.5 and its bundles, the extension libraries at &gt;= v1.1.2. See below.]]></summary></entry><entry><title type="html">RepoDB’s Complete Support to CancellationToken</title><link href="https://blogs.repodb.net/posts/2020/10/cancellation-token" rel="alternate" type="text/html" title="RepoDB’s Complete Support to CancellationToken" /><published>2020-10-03T00:00:00+00:00</published><updated>2020-10-03T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/10/cancellation-token</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/10/cancellation-token"><![CDATA[<p>Today, we are announcing the complete support of <a href="https://repodb.net">RepoDB</a> for the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=netcore-3.1">CancellationToken</a>.</p>

<p>Starting at version <a href="https://www.nuget.org/packages/RepoDb/1.12.4">v1.12.4</a> and its corresponding extended libraries for different DB Providers at version <a href="https://www.nuget.org/packages/RepoDb.SqlServer/1.1.1">1.1.1</a>, all the <code class="language-plaintext highlighter-rouge">Async</code> methods within the library will have an additional argument <code class="language-plaintext highlighter-rouge">cancellationToken</code> (defaulted to <code class="language-plaintext highlighter-rouge">CancellationToken.None</code> and/or <code class="language-plaintext highlighter-rouge">default</code>).</p>

<h3 id="how-will-it-affect-you">How will it affect you?</h3>

<p>When you upgrade, you can leverage the possibility of cancellable async operations. All the existing calls you made to any operations will not be affected (both compilation/signatures and the behaviors).</p>

<p>See the sample calls below for <a href="/https://repodb.net/operation/executenonquery">ExecuteNonQuery</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">tokenSource</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationTokenSource</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQueryAsync</span><span class="p">&lt;</span><span class="n">DateTime</span><span class="p">&gt;(</span><span class="s">"SELECT GETUTCDATE();"</span><span class="p">,</span>
        <span class="n">cancellationToken</span><span class="p">:</span> <span class="n">tokenSource</span><span class="p">.</span><span class="n">Token</span><span class="p">);</span>
    <span class="c1">// You can cancel the token anytime</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And for the <a href="/https://repodb.net/operation/query">Query</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">tokenSource</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationTokenSource</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="k">await</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAllAsync</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">cancellationToken</span><span class="p">:</span> <span class="n">tokenSource</span><span class="p">.</span><span class="n">Token</span><span class="p">);</span>
    <span class="c1">// You can cancel the token anytime</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And for the <a href="/https://repodb.net/operation/insert">Insert</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">tokenSource</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationTokenSource</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="k">await</span> <span class="n">connection</span><span class="p">.</span><span class="n">InsertAsync</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">,</span> <span class="kt">long</span><span class="p">&gt;(</span><span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">},</span>
    <span class="n">cancellationToken</span><span class="p">:</span> <span class="n">tokenSource</span><span class="p">.</span><span class="n">Token</span><span class="p">);</span>
    <span class="c1">// You can cancel the token anytime</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Such calls will be identical to all other <code class="language-plaintext highlighter-rouge">async</code> methods/operations within the library.</p>

<h3 id="breaking-changes">Breaking Changes</h3>

<p>There is one breaking change that will be covered by this release. But the use case for this is very minimal and/or almost 0.</p>

<p>If you have created your own customized <a href="/https://repodb.net/interface/idbhelper">IDbHelper</a> object, then, you need to change your signature by simply adding the <code class="language-plaintext highlighter-rouge">cancellationToken</code> argument in both methods defined in this interface.</p>

<h4 id="getfieldsasync">GetFieldsAsync</h4>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">DbField</span><span class="p">&gt;&gt;</span> <span class="nf">GetFieldsAsync</span><span class="p">(</span><span class="n">IDbConnection</span> <span class="n">connection</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">tableName</span><span class="p">,</span>
    <span class="n">IDbTransaction</span> <span class="n">transaction</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span>
    <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">default</span><span class="p">)</span>
</code></pre></div></div>

<h4 id="getscopeidentityasync">GetScopeIdentityAsync</h4>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;</span> <span class="nf">GetScopeIdentityAsync</span><span class="p">(</span><span class="n">IDbConnection</span> <span class="n">connection</span><span class="p">,</span>
    <span class="n">IDbTransaction</span> <span class="n">transaction</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span>
    <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">default</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="closing-note">Closing Note</h3>

<p>You can visit the actual <a href="https://github.com/mikependon/RepoDB/releases/tag/v1.12.4">release</a> from our Github page.</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[Today, we are announcing the complete support of RepoDB for the CancellationToken.]]></summary></entry><entry><title type="html">RepoDB version 1.12.3 - Bug and Hot Fixes for version 1.12.0</title><link href="https://blogs.repodb.net/posts/2020/10/repodb-bug-and-hot-fixes" rel="alternate" type="text/html" title="RepoDB version 1.12.3 - Bug and Hot Fixes for version 1.12.0" /><published>2020-10-03T00:00:00+00:00</published><updated>2020-10-03T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/10/repodb-bug-and-hot-fixes</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/10/repodb-bug-and-hot-fixes"><![CDATA[<p>When we announced the GA of <a href="https://www.nuget.org/packages/RepoDb/1.12.0">RepoDB v1.12.0</a>, many users were not able to pre-test the solutions even by having the 4 betas for the last 2 months. This has unfortunately led them to file the issues/bugs right after the releases.</p>

<p>The version <a href="https://www.nuget.org/packages/RepoDb/1.12.3">RepoDB v1.12.3</a> is a version that contains the fixes for those issues/bugs.</p>

<p>Allow us to explain and enumerate those issues.</p>

<h3 id="possible-compiler-collision-problem">Possible Compiler Collision Problem</h3>

<p>Only in the new compiler. In order for us to ensure that the collision will not happen during the caching of the AOT Compiled Expression, we need to consider the caching of the following.</p>

<ul>
  <li>HashCode of the Type</li>
  <li>HashCode of the Name of each DbDataReader Fields</li>
  <li>HashCode of the Type of each DbDataReader Fields</li>
  <li>HashCode of the Ordinal of each DbDataReader Fields - this is not yet there</li>
</ul>

<p>Without the ordinal caching, the collision may happen in various queries per entity model, resulting in multiple invalid casting exceptions (and/or data assignment issues). See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"SELECT Id, Name FROM Person;"</span><span class="p">);</span>
<span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"SELECT Name, Id FROM Person;"</span><span class="p">);</span>
</code></pre></div></div>

<p>This is critical; therefore, we issued the fix immediately.</p>

<h3 id="fetch-async-operations">Fetch Async Operations</h3>

<p>Affected by the latest release and core compiler updates, the current fetch operations are using the <a href="https://github.com/mikependon/RepoDB/blob/4361bebbcb947340ad1bc614b652e69fdc628be0/RepoDb.Core/RepoDb/Reflection/DataReader.cs#L24">DbDataReader.ToEnumerable()</a> operations. Therefore, all the Async fetch operations (i.e.: <a href="/https://repodb.net/operation/batchoperation">BatchQueryAsync</a>, <a href="/https://repodb.net/operation/query">QueryAsync</a> and <a href="/https://repodb.net/operation/executequery">ExecuteQueryAsync</a>) are not truly async methods.</p>

<p>As a fix, we again reverted the code to <a href="https://github.com/mikependon/RepoDB/blob/4361bebbcb947340ad1bc614b652e69fdc628be0/RepoDb.Core/RepoDb/Reflection/DataReader.cs#L53">DbDataReader.ToEnumerableAsync()</a> and made updates to the mentioned operations to have the proper chain of calls.</p>

<h3 id="nullexception-on-empty-where-expressions">NullException on Empty WHERE Expressions</h3>

<p>As reported by the user, a <code class="language-plaintext highlighter-rouge">NullReferenceException</code> is thrown if the <a href="/https://repodb.net/operation/query">Query</a> Expression is being equated to a <code class="language-plaintext highlighter-rouge">NULL</code> value.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="k">null</span><span class="p">);</span>
</code></pre></div></div>

<p>The issue happened because of the changes made in the latest compiler. In addition to that, we added the proper Integration Tests to cover this case.</p>

<h3 id="behavior-change-from-previous-versions">Behavior change from Previous Versions</h3>

<p>In the previous version, the code below was working for the table that has no <code class="language-plaintext highlighter-rouge">Primary</code> and <code class="language-plaintext highlighter-rouge">Identity</code> key.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">ColumnToUpdate</span> <span class="p">=</span> <span class="s">"Value"</span> <span class="p">};</span>
<span class="n">connection</span><span class="p">.</span><span class="nf">Update</span><span class="p">(</span><span class="s">"NonKeyedTable"</span><span class="p">,</span> <span class="n">model</span><span class="p">);</span>
</code></pre></div></div>

<p>It was affected by the changes during the updates to the core compiler; therefore, we needed to issue an immediate hotfix for it.</p>

<h3 id="additional-requests">Additional Requests</h3>

<p>A shared POCO between different data providers is not working if the DB Specific provider attribute is defined.</p>

<p>Let us say, you would like to use the model below for both PostgreSQL and SQLite.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">[</span><span class="nf">NpgsqlTypeMap</span><span class="p">(</span><span class="n">NpgsqlDbType</span><span class="p">.</span><span class="n">Json</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">ExtraInformation</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As stated with the attribute <a href="/https://repodb.net/attribute/npgsqltypemap">NpgsqlTypeMap</a>, such a model is catered for PostgreSQL; however, a user also would like to use such a model for SQLite, and there the exception is being thrown.</p>

<p>As an opportunity to further enhance the library, we have included the fixes for this. The fixes are not limited to the mentioned DB providers.</p>

<h3 id="closing-note">Closing Note</h3>

<p>You can visit the actual <a href="https://github.com/mikependon/RepoDB/releases/tag/v1.12.3">release</a> from our Github page</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[When we announced the GA of RepoDB v1.12.0, many users were not able to pre-test the solutions even by having the 4 betas for the last 2 months. This has unfortunately led them to file the issues/bugs right after the releases.]]></summary></entry><entry><title type="html">FSharp ClassHandler</title><link href="https://blogs.repodb.net/posts/2020/09/repodb-version-release-fsharp-classhandler" rel="alternate" type="text/html" title="FSharp ClassHandler" /><published>2020-09-24T00:00:00+00:00</published><updated>2020-09-24T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/09/repodb-version-release-fsharp-classhandler</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/09/repodb-version-release-fsharp-classhandler"><![CDATA[<p>Today, we are announcing the availability of <a href="https://www.nuget.org/packages/RepoDb/1.12.0">RepoDb v1.12.0</a>. The released packages also come with their bundles, the extension libraries at v1.1.0. See below.</p>

<ul>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqlServer/1.1.0">RepoDb.SqlServer v1.1.0</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqlServer.BulkOperations/1.1.0">RepoDb.SqlServer.BulkOperations v1.1.0</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.SqLite/1.1.0">RepoDb.SqLite v1.1.0</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.MySql/1.1.0">RepoDb.MySql v1.1.0</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.MySqlConnector/1.1.0">RepoDb.MySqlConnector v1.1.0</a></li>
  <li><a href="https://www.nuget.org/packages/RepoDb.PostgreSql/1.1.0">RepoDb.PostgreSql v1.1.0</a></li>
</ul>

<h3 id="tldr">TL;DR;</h3>

<p>The version <a href="https://www.nuget.org/packages/RepoDb/1.12.0">v1.12.0</a> together with its extensions (at <a href="https://repodb.net/release/core">v1.1.0</a>) release is one of the biggest suite releases of RepoDB. It has the major updates to its Core Features and Capabilities (Enhancements, Bug Fixes and Requests from the .NET Community). It also includes the initial support for the F# programming language; bundled with the new Enhanced Compiler, Class Handler and Advanced Dynamic Operation Invocations.</p>

<h3 id="highlights">Highlights</h3>

<p>Below is the list of the updates/changes covered by this release.</p>

<ul>
  <li><a href="#tldr">TL;DR;</a></li>
  <li><a href="#highlights">Highlights</a></li>
  <li><a href="#initial-support-to-fsharp">Initial Support to FSharp</a></li>
  <li><a href="#enhanced-compiler">Enhanced Compiler</a></li>
  <li><a href="#class-handler">Class Handler</a></li>
  <li><a href="#immutable-classes">Immutable Classes</a></li>
  <li><a href="#executequery-2nd-layer-cache">ExecuteQuery 2nd Layer Cache</a></li>
  <li><a href="#anonymous-type--expandoobject--idictionarystring-object">Anonymous Type / ExpandoObject / IDictionary&lt;string, object&gt;</a></li>
  <li><a href="#table-based-fluent-calls">Table-Based Fluent Calls</a></li>
  <li><a href="#complete-exposure-of-the-fields-argument">Complete Exposure of the ‘fields’ Argument</a></li>
  <li><a href="#typed-result-execution">Typed Result Execution</a></li>
  <li><a href="#support-to-table-valued-parameters-tvp">Support to Table-Valued Parameters (TVP)</a></li>
  <li><a href="#postgresql-truncate-reset-identity">PostgreSQL Truncate Reset Identity</a></li>
  <li><a href="#sqlite-autoincrement-vs-integer-primary-key">SQLite AUTOINCREMENT vs INTEGER PRIMARY KEY</a></li>
  <li><a href="#sqlite-insert-or-replace-vs-upsert">SQLite INSERT OR REPLACE vs UPSERT</a></li>
  <li><a href="#upsert-solution">Upsert Solution</a></li>
  <li><a href="#breaking-changes">Breaking Changes</a></li>
  <li><a href="#the-merge-argument-qualifiers-vs-fields">The Merge Argument (‘qualifiers’ vs ‘fields’)</a></li>
  <li><a href="#the-wherewhereorprimarykey-vs-what">The ‘Where/WhereOrPrimaryKey’ vs ‘What’</a></li>
  <li><a href="#the-datareadertoenumerable-method">The DataReader.ToEnumerable Method</a></li>
  <li><a href="#closing-note">Closing Note</a></li>
</ul>

<p>It is important to not skip the <a href="#breaking-changes">Breaking Changes</a> section.</p>

<h3 id="initial-support-to-fsharp">Initial Support to FSharp</h3>

<p>This release package comes with the initial support for the F# programming language together with the various requests from the F# community. Thank you to <a href="https://twitter.com/isaac_abraham">Isaac Abraham</a> and <a href="https://twitter.com/Daniel_Tuna">Angel Munoz</a> for being active collaborators here.</p>

<p>To start with, first, install the package. In this sample, we will use the SQL Server.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">Install</span><span class="p">-</span><span class="n">Package</span> <span class="n">RepoDb</span><span class="p">.</span><span class="n">SqlServer</span>
</code></pre></div></div>

<p>Then, initialize the bootstrapper.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">RepoDb</span><span class="p">.</span><span class="n">SqlServerBootstrap</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">();</span>
</code></pre></div></div>

<p>Then, create a model.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">module</span> <span class="n">Types</span> <span class="p">=</span>
    <span class="c1">//[&lt;CLIMutable&gt;]</span>
    <span class="n">type</span> <span class="n">Person</span> <span class="p">=</span> 
        <span class="p">{</span> <span class="n">Id</span><span class="p">:</span> <span class="n">int64</span>
          <span class="n">Name</span><span class="p">:</span> <span class="kt">string</span>
          <span class="n">Age</span><span class="p">:</span> <span class="kt">int</span>
          <span class="n">Address</span><span class="p">:</span> <span class="kt">string</span>
          <span class="n">IsActive</span><span class="p">:</span> <span class="kt">bool</span> <span class="p">}</span>
</code></pre></div></div>

<p>And also the table.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CREATE</span> <span class="n">TABLE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">Person</span><span class="p">]</span>
<span class="p">(</span>
	<span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">[</span><span class="n">bigint</span><span class="p">]</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="nf">IDENTITY</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">)</span> <span class="n">NOT</span> <span class="n">NULL</span><span class="p">,</span>
	<span class="p">[</span><span class="n">Name</span><span class="p">]</span> <span class="p">[</span><span class="n">nvarchar</span><span class="p">](</span><span class="m">128</span><span class="p">)</span> <span class="n">NOT</span> <span class="n">NULL</span><span class="p">,</span>
	<span class="p">[</span><span class="n">Age</span><span class="p">]</span> <span class="p">[</span><span class="kt">int</span><span class="p">]</span> <span class="n">NULL</span><span class="p">,</span>
	<span class="p">[</span><span class="n">Address</span><span class="p">]</span> <span class="p">[</span><span class="n">nvarchar</span><span class="p">](</span><span class="n">max</span><span class="p">)</span> <span class="n">NULL</span><span class="p">,</span>
	<span class="p">[</span><span class="n">IsActive</span><span class="p">]</span> <span class="p">[</span><span class="n">bit</span><span class="p">]</span> <span class="n">NOT</span> <span class="n">NULL</span>
<span class="p">)</span>
<span class="n">GO</span>

<span class="n">ALTER</span> <span class="n">TABLE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">Person</span><span class="p">]</span> <span class="n">ADD</span>  <span class="n">CONSTRAINT</span> <span class="p">[</span><span class="n">DF_Person_IsActive</span><span class="p">]</span>  <span class="nf">DEFAULT</span> <span class="p">((</span><span class="m">1</span><span class="p">))</span> <span class="n">FOR</span> <span class="p">[</span><span class="n">IsActive</span><span class="p">]</span>
<span class="n">GO</span>
</code></pre></div></div>

<p>Lastly, call the operations.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Query</span>
<span class="k">let</span> <span class="n">connection</span> <span class="p">=</span> <span class="p">(</span><span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">url</span><span class="p">))</span>
<span class="k">let</span> <span class="n">queryResult</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">QueryAll</span><span class="p">(</span><span class="s">"Person"</span><span class="p">).</span><span class="nf">AsList</span><span class="p">()</span>

<span class="c1">// Insert</span>
<span class="k">let</span> <span class="n">person</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">0L</span><span class="p">;</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">;</span> <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span><span class="p">;</span> <span class="n">Age</span> <span class="p">=</span> <span class="m">32</span><span class="p">;</span> <span class="n">IsActive</span> <span class="p">=</span> <span class="k">true</span> <span class="p">}</span>
<span class="k">let</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">,</span> <span class="n">int64</span><span class="p">&gt;(</span><span class="n">person</span><span class="p">)</span>

<span class="c1">// Insert (TableName)</span>
<span class="k">let</span> <span class="n">person</span> <span class="p">=</span> <span class="p">{|</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"James Smith"</span><span class="p">;</span> <span class="n">Age</span> <span class="p">=</span> <span class="m">32</span><span class="p">;</span> <span class="n">Address</span> <span class="p">=</span> <span class="s">"Washington"</span><span class="p">;</span> <span class="n">IsActive</span> <span class="p">=</span> <span class="k">true</span><span class="p">|}</span>
<span class="k">let</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">int64</span><span class="p">&gt;(</span><span class="n">ClassMappedNameCache</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(),</span> <span class="n">person</span><span class="p">)</span>

<span class="c1">// Merge</span>
<span class="k">let</span> <span class="n">person</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">0L</span><span class="p">;</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">;</span> <span class="p">}</span>
<span class="k">let</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Merge</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">person</span><span class="p">)</span>

<span class="c1">// Update</span>
<span class="k">let</span> <span class="n">person</span> <span class="p">=</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">0L</span><span class="p">;</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"James Doe"</span><span class="p">;</span> <span class="p">}</span>
<span class="k">let</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Update</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">person</span><span class="p">)</span>

<span class="c1">// Delete</span>
<span class="k">let</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Delete</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="m">10045</span><span class="p">)</span>
</code></pre></div></div>

<p>By default, all the functionalities and features written for the C# programming language are also inherited by the F# programming language. It is also important to take note that the <code class="language-plaintext highlighter-rouge">CLIMutable</code> attribute can be eliminated from all your models starting from this release.</p>

<p><strong>Disclaimer:</strong> The option types in F# are not supported if it is being placed at the <a href="/feature/classhandlers">ClassHandler</a> and <a href="/feature/propertyhandlers">PropertyHandler</a> objects.</p>

<h3 id="enhanced-compiler">Enhanced Compiler</h3>

<p>The core compiler of RepoDB has been rewritten from being a monolithic codebase to multiple smaller codebases. All the compiler classes needed for the AOT compilations have been split into several partial classes. With these updates, the code is much easier, neater and cleaner.</p>

<p>The reasons and the motivations behind this are the following.</p>

<ul>
  <li>The old compiler code is harder to maintain; RepoDB itself is becoming more complex. The new compiler is easy, simple, neat and clean. It adheres to the clean-code principles.</li>
  <li>If the Conversion is Automatic, the old compiler does multiple conversions of the expression, thus slowing down the process.</li>
  <li>There is a lot of repetitive code in the old compiler which has been completely eliminated.</li>
  <li>To simplify error handling, it was also introduced in the most critical parts of the new compiler, thus giving better error messages to the users of the library.</li>
  <li>Difficulty of the implementation of extended functionality (i.e.: <a href="/feature/classhandlers">ClassHandler</a>, <a href="/feature/propertyhandlers">PropertyHandler</a>). It is very easy to do such things with the new compiler.</li>
</ul>

<p>In addition to this, with the new compiler, the Anonymous Type Param Argument is now being cached and compiled ahead-of-time (AOT), thus making this library more performant and much more memory-efficient when calling the underlying Execute methods (i.e.: <a href="/operation/executequery">ExecuteQuery</a>, <a href="/operation/executenonquery">ExecuteNonQuery</a>, <a href="/operation/executescalar">ExecuteScalar</a>, <a href="/operation/executereader">ExecuteReader</a> and <a href="/operation/executequerymultiple">ExecuteQueryMultiple</a>). See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [Person] WHERE Id = @Id;"</span><span class="p">,</span>
    <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">});</span>
</code></pre></div></div>

<p>Not to mention, with the new enhanced compiler, the library even becomes faster and more efficient than it was before.</p>

<h3 id="class-handler">Class Handler</h3>

<p>The feature <a href="feature/classhandlers">ClassHandler</a> has been introduced as part of the package. It allows you to handle the event during the serialization/deserialization process of the class model and the DbDataReader object (inbound/outbound).</p>

<p>First, implement a class handler by simply implementing the <a href="/interface/iclasshandler">IClassHandler</a> interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">PersonClassHandler</span> <span class="p">:</span> <span class="n">IClassHandler</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Person</span> <span class="nf">Get</span><span class="p">(</span><span class="n">Person</span> <span class="n">entity</span><span class="p">,</span>
        <span class="n">DbDataReader</span> <span class="n">reader</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">entity</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Person</span> <span class="nf">Set</span><span class="p">(</span><span class="n">Person</span> <span class="n">entity</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">entity</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, map the class handler into your model.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">ClassHandler</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">PersonClassHandler</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You can also use the <a href="/mapper/fluentmapper">FluentMapper</a> class if you wish to have attribute-free models.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">FluentMapper</span>
    <span class="p">.</span><span class="n">Entity</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="n">ClassHandler</span><span class="p">&lt;</span><span class="n">PersonClassHandler</span><span class="p">&gt;();</span>
</code></pre></div></div>

<p>Or, the <a href="/mapper/classhandlermapper">ClassHandlerMapper</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ClassHandlerMapper</span>
    <span class="p">.</span><span class="n">Add</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">,</span> <span class="n">PersonClassHandler</span><span class="p">&gt;(</span><span class="k">true</span><span class="p">);</span>
</code></pre></div></div>

<p>After the mappings, when you call any of the push operations (i.e.: <a href="/operation/insert">Insert</a>, <a href="/operation/merge">Merge</a> and <a href="/operation/update">Update</a>), the <code class="language-plaintext highlighter-rouge">Set()</code> method of the property handler will be invoked, thus allowing you to intercept the information prior to the actual execution against the database.</p>

<p>On the other hand, when you call any of the push operations (i.e.: <a href="/operation/query">Query</a>, <a href="/operation/queryall">QueryAll</a>, <a href="/operation/batchquery">BatchQuery</a> and even the raw-SQL based <a href="/operation/executequery">ExecuteQuery</a>), the <code class="language-plaintext highlighter-rouge">Get()</code> method of the property handler will be invoked for you to verify the extracted information prior to returning it to the caller.</p>

<h3 id="immutable-classes">Immutable Classes</h3>

<p>In the previous versions, unhandled exception messages are being thrown if the immutable classes are used as the models. However, in order to strengthen the support for the F# programming language, support for immutable classes has been introduced.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span>
        <span class="kt">string</span> <span class="n">name</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="n">id</span><span class="p">;</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The name of the constructor arguments must be identical to the name of the properties. Only the matching arguments and properties will be processed during the hydration process. Therefore, to be safe, ensure that the names of the target arguments are equal to the DbDataReader fields, no matter what.</p>

<p>It is also important to take note that you can even combine the constructor arguments together with the public properties within the model. See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span>
        <span class="kt">string</span> <span class="n">name</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="n">id</span><span class="p">;</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">Addres</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Writable</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsActive</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Writable</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="executequery-2nd-layer-cache">ExecuteQuery 2nd Layer Cache</h3>

<p>Historically, the 2nd Layer cache capability was not introduced in the <a href="/operation/executequery">ExecuteQuery</a> operation for the purpose of avoiding the collisions. However, since this release has supported the table-based calls for the Entity Model, it has also validated this feature; therefore, starting from this release, the 2nd Layer cache will be supported in this method.</p>

<p>Let us say you have a cache factory named <code class="language-plaintext highlighter-rouge">MemoryCacheFactory</code> that creates a single instance of <a href="/interface/icache">ICache</a> object. Then, the code below is now valid.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">memoryCache</span> <span class="p">=</span> <span class="n">MemoryCacheFactory</span><span class="p">.</span><span class="nf">Create</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM Product;"</span><span class="p">,</span>
        <span class="n">cacheKey</span><span class="p">:</span> <span class="s">"AllProducts"</span><span class="p">,</span> <span class="n">cache</span><span class="p">:</span> <span class="n">memoryCache</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The first call will query the database; the 2nd call will query the data from the supplied cache object. By default, the cache item expires within 180 minutes, but such settings can be changed by simply passing the value in the <code class="language-plaintext highlighter-rouge">cacheItemExpiration</code> argument during the calls.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM Product;"</span><span class="p">,</span>
    <span class="n">cacheKey</span><span class="p">:</span> <span class="s">"AllProducts"</span><span class="p">,</span>
    <span class="n">cache</span><span class="p">:</span> <span class="n">memoryCache</span><span class="p">,</span>
    <span class="n">cacheItemExpiration</span><span class="p">:</span> <span class="m">300</span> <span class="cm">/* 5 hours */</span><span class="p">);</span>
</code></pre></div></div>

<p>If you are working with a repository (i.e.: <a href="/class/baserepository">BaseRepository</a> and <a href="/class/dbrepository">DbRepository</a>), you do not need to pass the instance of the <a href="/interface/icache">ICache</a> object. It is handled by the repository internally through the <a href="/class/memorycache">MemoryCache</a> object.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">repository</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DbRepository</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM Product;"</span><span class="p">,</span>
        <span class="n">cacheKey</span><span class="p">:</span> <span class="s">"AllProducts"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent Calls Collisions: For as long as you are pointing to the same <a href="/interface/icache">ICache</a> object, you can collide the information with the fluent calls.</p>

<p>The call below is valid and collides with the cache item specified in the execute method above.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">memoryCache</span> <span class="p">=</span> <span class="n">MemoryCacheFactory</span><span class="p">.</span><span class="nf">Create</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;(</span><span class="n">cacheKey</span><span class="p">:</span> <span class="s">"AllProducts"</span><span class="p">,</span>
        <span class="n">cache</span><span class="p">:</span> <span class="n">memoryCache</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Of course, if the type of the cached items is not equal to the target result type, then an exception will be thrown. See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">memoryCache</span> <span class="p">=</span> <span class="n">MemoryCacheFactory</span><span class="p">.</span><span class="nf">Create</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">suppliers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Supplier</span><span class="p">&gt;(</span><span class="n">cacheKey</span><span class="p">:</span> <span class="s">"AllProducts"</span><span class="p">,</span>
        <span class="n">cache</span><span class="p">:</span> <span class="n">memoryCache</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="anonymous-type--expandoobject--idictionarystring-object">Anonymous Type / ExpandoObject / IDictionary&lt;string, object&gt;</h3>

<p>It is not common for the ORM to support the Anonymous Type Resultset; however, in RepoDB we have supported this. This is also a case for this library to completely support the F# programming language.</p>

<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">connection</span><span class="p">.</span><span class="nc">QueryAll</span><span class="o">&lt;{|</span> <span class="nc">Id</span> <span class="p">:</span> <span class="n">int64</span><span class="p">;</span> <span class="nc">Name</span> <span class="p">:</span> <span class="kt">string</span>  <span class="o">|}&gt;</span> <span class="s2">"Person"</span>
</code></pre></div></div>

<p>The code snippet above is for F# programming language, and below is the equivalent C# programming language.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Create a type def</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">typeDef</span> <span class="p">=</span> <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="k">default</span><span class="p">(</span><span class="kt">long</span><span class="p">),</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="k">default</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">Call</span><span class="p">(</span><span class="n">typeDef</span><span class="p">,</span> <span class="s">"Person"</span><span class="p">);</span>
    <span class="c1">// Process the 'people' as anonymous</span>
<span class="p">}</span>

<span class="k">private</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">Call</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">typeDef</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">table</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">table</span><span class="p">);)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Historically, both the ExpandoObject and the IDictionary&lt;string, object&gt; objects are already supported as the query resultset when fetching the data from the database, but only if you are using the table-based calls like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">QueryAll</span><span class="p">(</span><span class="s">"Person"</span><span class="p">);</span>
</code></pre></div></div>

<p>On this release, the calls below will also return the ExpandoObject.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="kt">dynamic</span><span class="p">&gt;(</span><span class="s">"Person"</span><span class="p">);</span>
<span class="c1">// Or</span>
<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">ExpandoObject</span><span class="p">&gt;(</span><span class="s">"Person"</span><span class="p">);</span>
</code></pre></div></div>

<p>Or, you can even infer as IDictionary&lt;string, object&gt;.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;(</span><span class="s">"Person"</span><span class="p">);</span>
</code></pre></div></div>

<p>And below is the equivalent for F# programming language.</p>

<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nc">QueryAll</span><span class="p">&lt;</span><span class="nc">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="n">obj</span><span class="o">&gt;&gt;</span> <span class="s2">"Person"</span><span class="p">;</span>
</code></pre></div></div>

<p>It is also important that this feature is not limited to the fluent calls. You can also use it in the actual <a href="/operation/executequery">ExecuteQuery</a> operation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT * FROM Person;"</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;(</span><span class="n">sql</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="table-based-fluent-calls">Table-Based Fluent Calls</h3>

<p>In the previous version, there is no way for you to reuse the model unless you are working with the dynamics and Anonymous Types. In this release, you can reuse the exact same single model for whatever operations you would like.</p>

<p>Let us say we created a <code class="language-plaintext highlighter-rouge">Person</code> model.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And by doing the code below, it directly queries the <code class="language-plaintext highlighter-rouge">Person</code> table.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;();</span>
</code></pre></div></div>

<p>Moving forward, you can use the same model for as long as it defines the characteristics of the records. Below is the code that queries the <code class="language-plaintext highlighter-rouge">Supplier</code> and <code class="language-plaintext highlighter-rouge">Customer</code> tables using the same <code class="language-plaintext highlighter-rouge">Person</code> model.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"Customer"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">suppliers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"Supplier"</span><span class="p">);</span>
</code></pre></div></div>

<p>The functionality is also extended to all other operations (i.e.: <a href="/operation/insert">Insert</a>, <a href="/operation/merge">Merge</a>, <a href="/operation/update">Update</a>, etc).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Person</span>
<span class="p">{</span>
    <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span>
<span class="p">};</span>
<span class="kt">var</span> <span class="n">customerId</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">supplierId</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"Supplier"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
</code></pre></div></div>

<p>The importance of this feature is to allow you to eliminate the repetitive models you are creating when designing an application. The ratio of the cases may not be high, but it is quite important in some cases.</p>

<h3 id="complete-exposure-of-the-fields-argument">Complete Exposure of the ‘fields’ Argument</h3>

<p>This new feature is requested by the community to make the library a completely dynamic ORM. Historically, you can only update specific columns if you are using the dynamics and/or Anonymous Types based calls. See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
    <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
<span class="p">});</span>
</code></pre></div></div>

<p>The call above inserts a record into the <code class="language-plaintext highlighter-rouge">Customer</code> table targeting only the <code class="language-plaintext highlighter-rouge">Name</code> and the <code class="language-plaintext highlighter-rouge">Address</code> columns. Other columns that are not a part of the Anonymous Type you passed will not be part of the execution.</p>

<p>However, in this release, you can do such a thing even with the actual class models. Simply specify the list of the fields you wish to be covered by the operation in the <code class="language-plaintext highlighter-rouge">fields</code> argument.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
<span class="p">{</span>
    <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
    <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span><span class="p">,</span>
    <span class="n">IsActive</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
    <span class="n">CreatedDateUtc</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span>
<span class="p">};</span>
<span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Address</span>
<span class="p">});</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customer</span><span class="p">,</span> <span class="n">fields</span><span class="p">:</span> <span class="n">fields</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Among all the properties that the <code class="language-plaintext highlighter-rouge">Customer</code> class model has, only the <code class="language-plaintext highlighter-rouge">Name</code> and <code class="language-plaintext highlighter-rouge">Address</code> columns are being processed.</p>

<p>You can as well do it in literal string like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
<span class="p">{</span>
    <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
    <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span><span class="p">,</span>
    <span class="n">IsActive</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
    <span class="n">CreatedDateUtc</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">,</span>
    <span class="n">UpdatedDateUtc</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span>
<span class="p">};</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customer</span><span class="p">,</span>
        <span class="n">fields</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="s">"Address"</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">fields</code> argument is now exposed to all the important push and pull operations (i.e.: <a href="/operation/query">Query</a>, <a href="/operation/merge">Merge</a>, <a href="/operation/update">Update</a> and all the corresponding batch operations).</p>

<h3 id="typed-result-execution">Typed Result Execution</h3>

<p>This was a very simple yet quite important feature awaited by some of the users of the library. On this release, the Type Result set is now supported.</p>

<p>Historically, if you wish to query a single column from the table, you are required to return it as dynamics or an explicit class model.</p>

<p>Via a dynamic object of type <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Returns an IEnumerable&lt;ExpandoObject&gt;</span>
<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">ExecuteQuery</span><span class="p">(</span><span class="s">"SELECT Name FROM Person;"</span><span class="p">);</span>
</code></pre></div></div>

<p>Or, with a class model with single property.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And do the query like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ExecuteQuery</span>
<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="s">"SELECT Name FROM Person;"</span><span class="p">);</span>

<span class="c1">// Fluent QueryAll</span>
<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;();</span>
</code></pre></div></div>

<p>Moving forward, you can do it like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// String</span>
<span class="kt">var</span> <span class="n">names</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="s">"SELECT Name FROM Person;"</span><span class="p">);</span>

<span class="c1">// Long</span>
<span class="kt">var</span> <span class="n">ids</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="s">"SELECT Id FROM Person;"</span><span class="p">);</span>
</code></pre></div></div>

<p>Without even creating a model, you can directly infer the result to any .NET CLR type.</p>

<p>You can even do it with the enumerations.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">enum</span> <span class="n">Gender</span>
<span class="p">{</span>
    <span class="n">Male</span><span class="p">,</span>
    <span class="n">Female</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And do the query like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT Gender FROM Person WHERE Name = @Name;"</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">gender</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Gender</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span> <span class="p">});</span>
</code></pre></div></div>

<p>Also, as a part of this package release, if you have a table with a single column (which is most likely not happening at all), you can directly query the records like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">subjectNames</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="s">"Subject"</span><span class="p">);</span>
</code></pre></div></div>

<p>Or just force a fluent call for single field.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">productNames</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="s">"Product"</span><span class="p">,</span>
     <span class="n">fields</span><span class="p">:</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"Name"</span><span class="p">));</span>
</code></pre></div></div>

<h3 id="support-to-table-valued-parameters-tvp">Support to Table-Valued Parameters (TVP)</h3>

<p>The current release is now fully acknowledging the support for the Table-Valued Parameters (TVP) via User-Defined Types (UDT) from SQL Server.</p>

<p>To do this, simply create a UDT from the database, and then create a stored procedure that accepts that UDT type. You can follow these <a href="https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters">guidelines</a> from Microsoft.</p>

<p>Let us say, you created a stored procedure named <code class="language-plaintext highlighter-rouge">sp_InsertPerson</code> that accepts the UDT named <code class="language-plaintext highlighter-rouge">PersonType</code>. The stored procedure is merging the received information into the actual table <code class="language-plaintext highlighter-rouge">Person</code>, then returns all the newly inserted records.</p>

<p>To call such thing, simply create a <code class="language-plaintext highlighter-rouge">DataTable</code> and set the <code class="language-plaintext highlighter-rouge">TableName</code> property equals to the name of the UDT.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">table</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DataTable</span><span class="p">();</span>
<span class="n">table</span><span class="p">.</span><span class="n">TableName</span> <span class="p">=</span> <span class="s">"[dbo].[PersonType]"</span><span class="p">;</span> <span class="c1">// Name of the UDT</span>
<span class="c1">// Create the 'table' columns/rows</span>
</code></pre></div></div>

<p>Then, simply call the stored procedure like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"EXEC [sp_InsertPerson] @PersonTable = @Table;"</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Table</span> <span class="p">=</span> <span class="n">table</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="postgresql-truncate-reset-identity">PostgreSQL Truncate Reset Identity</h3>

<p>Historically, RepoDB’s truncate operation for <a href="https://www.nuget.org/packages/RepoDb.PostgreSql/">RepoDb.PostgreSql</a> has not been auto-resetting the identity seed to the beginning. However, in order for the <a href="/operation/truncate">Truncate</a> operation to be identical to the other DB providers, in this package release, we now force the identity seed to reset back to the beginning.</p>

<p>When you call the operation like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">NpgsqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="n">connection</span><span class="p">.</span><span class="n">Truncate</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The following SQL Statement will be generated.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; TRUNCATE TABLE \"Person\" RESTART IDENTITY ;
</code></pre></div></div>

<p><strong>Note:</strong> This feature update could be considered a breaking change in some cases, specifically when processing the data.</p>

<h3 id="sqlite-autoincrement-vs-integer-primary-key">SQLite AUTOINCREMENT vs INTEGER PRIMARY KEY</h3>

<p>In the previous version, the identity field (and/or Auto-Incremented column) is only being identified if the column is <code class="language-plaintext highlighter-rouge">AUTOINCREMENT</code>. See below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CREATE</span> <span class="n">TABLE</span> <span class="n">IF</span> <span class="n">NOT</span> <span class="n">EXISTS</span> <span class="p">[</span><span class="n">Person</span><span class="p">]</span>
<span class="p">(</span>
    <span class="n">Id</span> <span class="n">INTEGER</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
    <span class="n">Name</span> <span class="n">TEXT</span><span class="p">,</span>
    <span class="n">Age</span> <span class="n">INTEGER</span><span class="p">,</span>
    <span class="n">CreatedDateUtc</span> <span class="n">DATETIME</span>
<span class="p">);</span>
</code></pre></div></div>

<p>However, referring to the actual <a href="https://sqlite.org/autoinc.html">Auto-Increment</a> documentation of SQLite, the column <code class="language-plaintext highlighter-rouge">INTEGER PRIMARY KEY</code> is also automatically converted to be auto-incremented. Therefore, in this package release, the <a href="https://www.nuget.org/packages/RepoDb.SqLite/">RepoDb.SqLite</a> is also parsing the <code class="language-plaintext highlighter-rouge">INTEGER PRIMARY KEY</code> as an identity field (and/or Auto-Incremented column).</p>

<h3 id="sqlite-insert-or-replace-vs-upsert">SQLite INSERT OR REPLACE vs UPSERT</h3>

<p>We internally found a major bug in the <a href="/operation/merge">Merge</a> operation of the <a href="https://www.nuget.org/packages/RepoDb.SqLite/">RepoDb.SqLite</a> extension library. In the past, it used the <code class="language-plaintext highlighter-rouge">INSERT OR REPLACE</code> keyword to merge the changes towards the database. The major problem with this is that the <code class="language-plaintext highlighter-rouge">INSERT OR REPLACE</code> does not work for certain columns.</p>

<p><strong>Note:</strong> Merge is referring to a functionality of inserting a record in the database if not present, or otherwise updating it.</p>

<p>Let us say you have this class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Age</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">DateTime</span> <span class="n">CreatedDateUtc</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And you have the table below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CREATE</span> <span class="n">TABLE</span> <span class="n">IF</span> <span class="n">NOT</span> <span class="n">EXISTS</span> <span class="p">[</span><span class="n">Person</span><span class="p">]</span>
<span class="p">(</span>
    <span class="n">Id</span> <span class="n">INTEGER</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
    <span class="n">Name</span> <span class="n">TEXT</span><span class="p">,</span>
    <span class="n">Age</span> <span class="n">INTEGER</span><span class="p">,</span>
    <span class="n">CreatedDateUtc</span> <span class="n">DATETIME</span>
<span class="p">);</span>
</code></pre></div></div>

<p>And you would like to only merge on the <code class="language-plaintext highlighter-rouge">Name</code> column with the qualifier <code class="language-plaintext highlighter-rouge">Id</code>, like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SQLiteConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">,</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"James Doe"</span>
    <span class="p">};</span>
    <span class="n">connection</span><span class="p">.</span><span class="nf">Merge</span><span class="p">(</span><span class="s">"Person"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, the operation above will not work as expected if the record is already present in the database.</p>

<p>The generated SQL of the above code snippet is below.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; INSERT OR REPLACE INTO [Person] ( Id, Name ) VALUES ( @Id, @Name ); SELECT CAST([Id], INTEGER) AS [Result];
</code></pre></div></div>

<p>What happened behind the scenes? Even though the other columns (i.e.: <code class="language-plaintext highlighter-rouge">Age</code> and <code class="language-plaintext highlighter-rouge">CreatedDateUtc</code> columns) are not part of the statement, the <code class="language-plaintext highlighter-rouge">INSERT OR REPLACE</code> keyword is setting them to <code class="language-plaintext highlighter-rouge">NULL</code> by default.</p>

<h3 id="upsert-solution">Upsert Solution</h3>

<p>The solution we introduced for this is to switch the <a href="https://www.nuget.org/packages/RepoDb.SqLite/">RepoDb.SqLite</a> extension library to use the upsert technique. The upsert keyword stands for <code class="language-plaintext highlighter-rouge">Update/Insert</code>.</p>

<p>We implemented it on the client side. Therefore, the logic of identifying the presence of the data will happen within the application (via the <a href="/operation/exsists">Exists</a> operation).</p>

<p>Let us say, you do the call like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SQLiteConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">person</span> <span class="p">=</span> <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">,</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"James Doe"</span>
    <span class="p">};</span>
    <span class="n">connection</span><span class="p">.</span><span class="nf">Merge</span><span class="p">(</span><span class="s">"Person"</span><span class="p">,</span> <span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then, the library will do the following logic.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">connection</span><span class="p">.</span><span class="nf">Exists</span><span class="p">(</span><span class="n">person</span><span class="p">))</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Update</span><span class="p">(</span><span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span><span class="n">person</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It is important to take note that this change is only for the <a href="https://www.nuget.org/packages/RepoDb.SqLite/">RepoDb.SqLite</a> extension library, not affecting the other DB providers.</p>

<p>With this update, the <a href="/operation/mergeall">MergeAll</a> operation for <a href="https://www.nuget.org/packages/RepoDb.SqLite/">RepoDb.SqLite</a> has been switched to an <code class="language-plaintext highlighter-rouge">atomic</code> operation and is no longer processed via <code class="language-plaintext highlighter-rouge">batch</code> operations.</p>

<p>The trigger for this is the <a href="https://github.com/mikependon/RepoDB/blob/master/RepoDb.SqLite/RepoDb.SqLite/DbSettings/SqLiteDbSetting.cs">SqLiteDbSetting</a> object’s <code class="language-plaintext highlighter-rouge">IsUseUpsert</code> property.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="nf">SqLiteDbSetting</span><span class="p">(</span><span class="kt">bool</span> <span class="n">isExecuteReaderDisposable</span><span class="p">)</span>
    <span class="p">:</span> <span class="k">base</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">AreTableHintsSupported</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
    <span class="n">AverageableType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="kt">double</span><span class="p">);</span>
    <span class="n">ClosingQuote</span> <span class="p">=</span> <span class="s">"]"</span><span class="p">;</span>
    <span class="n">DefaultSchema</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
    <span class="n">IsDirectionSupported</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
    <span class="n">IsExecuteReaderDisposable</span> <span class="p">=</span> <span class="n">isExecuteReaderDisposable</span><span class="p">;</span>
    <span class="n">IsMultiStatementExecutable</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="n">IsPreparable</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="n">IsUseUpsert</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="n">OpeningQuote</span> <span class="p">=</span> <span class="s">"["</span><span class="p">;</span>
    <span class="n">ParameterPrefix</span> <span class="p">=</span> <span class="s">"@"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="breaking-changes">Breaking Changes</h3>

<p>In this section, we will enumerate some of the known breaking changes from the previous releases of this library. It is important for you to spend time reading this.</p>

<h3 id="the-merge-argument-qualifiers-vs-fields">The Merge Argument (‘qualifiers’ vs ‘fields’)</h3>

<p>If you had called the <a href="/operation/merge">Merge</a> operation with the list of <a href="/class/field">Field</a> objects as the second argument and had not specified the argument name during the calls, then that would trigger a compilation error moving forward (see below).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="nf">GetMergeablePeople</span><span class="p">();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
        <span class="n">e</span><span class="p">.</span><span class="n">DateOfBirth</span>
    <span class="p">});</span>
    <span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Merge</span><span class="p">&lt;</span><span class="n">People</span><span class="p">&gt;(</span><span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Historically, the second argument is the <code class="language-plaintext highlighter-rouge">qualifiers</code>; however, in the current release, the <code class="language-plaintext highlighter-rouge">fields</code> argument is also placed as the second argument in the overloaded method, therefore invalidating the calls above.</p>

<p>To fix the issue, simply specify the name of the arguments to your call like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">DateOfBirth</span>
<span class="p">});</span>
<span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Merge</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
</code></pre></div></div>

<p>And if calling for the fields.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">DateOfBirth</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">IsActive</span>
<span class="p">});</span>
<span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Merge</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">people</span><span class="p">,</span> <span class="n">fields</span><span class="p">:</span> <span class="n">fields</span><span class="p">);</span>
</code></pre></div></div>

<p>And if you are using both.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">DateOfBirth</span>
<span class="p">});</span>
<span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="n">Parse</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
<span class="p">{</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">DateOfBirth</span><span class="p">,</span>
    <span class="n">e</span><span class="p">.</span><span class="n">IsActive</span>
<span class="p">});</span>
<span class="kt">var</span> <span class="n">mergedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Merge</span><span class="p">&lt;</span><span class="n">People</span><span class="p">&gt;(</span><span class="n">people</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">,</span> <span class="n">fields</span><span class="p">:</span> <span class="n">fields</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="the-wherewhereorprimarykey-vs-what">The ‘Where/WhereOrPrimaryKey’ vs ‘What’</h3>

<p>In the previous version, if you had forced the use of the named argument for <code class="language-plaintext highlighter-rouge">whereOrPrimaryKey</code> and/or <code class="language-plaintext highlighter-rouge">where</code> when calling any of the push/pull operations, that may have caused a compiler error.</p>

<p>In the current release, we renamed the <code class="language-plaintext highlighter-rouge">whereOrPrimaryKey</code> and some of the placements of the <code class="language-plaintext highlighter-rouge">where</code> argument into <code class="language-plaintext highlighter-rouge">what</code>. The motivation behind this is that <code class="language-plaintext highlighter-rouge">what</code> now supports 3 contexts.</p>

<ul>
  <li>Entity Model / Type / Anonymous Type</li>
  <li>PrimaryKey</li>
  <li>IdentityKey</li>
</ul>

<p>Historically, the identity key was not being identified.</p>

<p>So, all the previous calls like below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">whereOrPrimaryKey</span><span class="p">:</span> <span class="m">10045</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This must be refactored to look like the following.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="n">what</span><span class="p">:</span> <span class="m">10045</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or, simply eliminate the named argument.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">people</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Person</span><span class="p">&gt;(</span><span class="m">10045</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The update must be done to the other methods that accept the mentioned stale arguments (i.e.: <a href="/operation/delete">Delete</a>, <a href="/operation/update">Update</a> and the others).</p>

<h3 id="the-datareadertoenumerable-method">The DataReader.ToEnumerable Method</h3>

<p>The method that is being used to extract the DbDataReader object into a target .NET CLR Type has been completely modified. In the previous version, the method named <code class="language-plaintext highlighter-rouge">ToEnumerable</code> with a signature like below is present, together with its corresponding <code class="language-plaintext highlighter-rouge">async</code> method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">ToEnumerable</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">DbDataReader</span> <span class="n">reader</span><span class="p">,</span>
    <span class="n">IDbConnection</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span>
    <span class="n">IDbTransaction</span> <span class="n">transaction</span> <span class="p">=</span> <span class="k">null</span><span class="p">);</span>
</code></pre></div></div>

<p>However, in the new version, the method signature has been completely modified with the one below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ToEnumerable</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">DbDataReader</span> <span class="n">reader</span><span class="p">,</span>
    <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">DbField</span><span class="p">&gt;</span> <span class="n">dbFields</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span>
    <span class="n">IDbSetting</span> <span class="n">dbSetting</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>         
</code></pre></div></div>

<p>Also, the <code class="language-plaintext highlighter-rouge">async</code> method has been removed as it is not necessary anymore.</p>

<p>The rationale behind this is the following.</p>

<ul>
  <li>Eliminate the DB calls from the compiler.</li>
  <li>Support the Enhanced Compiler scenarios.</li>
  <li>Simplify the calls of the possible users.</li>
</ul>

<h3 id="closing-note">Closing Note</h3>

<p>The release updates also come with various requests from the community, bug fixes, enhancements and major refactoring. It is important to see the detailed updates from the <a href="/release/core">Releases</a> page and/or by visiting the actual release page for this version at the Github <a href="https://github.com/mikependon/RepoDB/releases/tag/v1.12.0">releases</a> page.</p>

<p>We also would like to extend our warm thanks to all the contributors, the collaborators and the issue reporters.</p>

<p>Please do not f</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[Today, we are announcing the availability of RepoDb v1.12.0. The released packages also come with their bundles, the extension libraries at v1.1.0. See below.]]></summary></entry><entry><title type="html">C#: Bulk Operations for .NET Core</title><link href="https://blogs.repodb.net/posts/2020/04/csharp-bulk-operations-for-net-core" rel="alternate" type="text/html" title="C#: Bulk Operations for .NET Core" /><published>2020-04-06T00:00:00+00:00</published><updated>2020-04-06T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/04/csharp-bulk-operations-for-net-core</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/04/csharp-bulk-operations-for-net-core"><![CDATA[<p>We would like to share with you the latest and greatest updates of RepoDB ORM. Recently, we just published the complete out-of-the-box support of Bulk Operations for SQL Server in .NET data access space.</p>

<p>The actual repository can be found at <a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations">RepoDb.SqlServer.BulkOperations</a>.</p>

<h4 id="the-updates-cover-the-following-awaited-methods">The updates cover the following awaited methods</h4>

<ul>
  <li><code class="language-plaintext highlighter-rouge">BulkDelete</code> (<code class="language-plaintext highlighter-rouge">BulkDeleteAsync</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">BulkInsert</code> (<code class="language-plaintext highlighter-rouge">BulkInsertAsync</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">BulkMerge</code> (<code class="language-plaintext highlighter-rouge">BulkMergeAsync</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">BulkUpdate</code> (<code class="language-plaintext highlighter-rouge">BulkUpdateAsync</code>)</li>
</ul>

<p>If you are usually working with large datasets, then this feature is for you. By using this, it will drastically improve the performance of your application, together with increasing your productivity during development.</p>

<p>In addition, it will remove your worries about writing and maintaining the complex and tedious code snippets (implementation complexity) just to achieve your “BASIC” goals with high-performance.</p>

<p><em>As an author and being an OSS contributor, I am trying to further improve the experience of most .NET Developers when it comes to data accessibility. The features within the library are free and will always be. In return, I only like to hear your thoughts, feedback and experiences about this library. With this, we can help each other to further improve it.</em></p>

<h3 id="the-benefits-of-using-the-bulk-operations">The benefits of using the Bulk Operations</h3>

<p><strong>Nothing else, but PERFORMANCE!</strong></p>

<p>Although the same exact goal can be achieved by Batch Operations (i.e.: <a href="/operation/deleteall">DeleteAll</a>, <a href="/operation/insertall">InsertAll</a>, <a href="/operation/mergeall">MergeAll</a> and <a href="/operation/updateall">UpdateAll</a>), by leveraging the real Bulk Operations functionalities, you are extremely improving the performance of your data manipulation with a huge-percentage gap.</p>

<p>To explain further, when you only use the Batch operations, it only batches the multiple atomic activities and still makes multiple round-trips from your application into the database server. However, when you use the Bulk operations, you are bringing all the data from the application into the database server at once and at the same time ignoring some database specific activities (i.e.: <code class="language-plaintext highlighter-rouge">Logging</code>, <code class="language-plaintext highlighter-rouge">Audits</code>, <code class="language-plaintext highlighter-rouge">Data-Type Checks</code>, <code class="language-plaintext highlighter-rouge">Constraints</code>, etc) behind the scene, thus gives you maximum performance during the operation.</p>

<h3 id="how-does-it-work">How does it work?</h3>

<p>It is leveraging the ADO.NET <a href="https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopy?view=dotnet-plat-ext-7.0">SqlBulkCopy</a> class (both <code class="language-plaintext highlighter-rouge">System.Data.SqlClient/Microsoft.Data.SqlClient</code>).</p>

<p>For the <a href="/operation/bulkinsert">BulkInsert</a> operation, it simply calls the <em>WriteToServer</em> method to bring all the data from the application into the database. No additional logic is implied.</p>

<p>For <a href="/operation/bulkdelete">BulkDelete</a>, <a href="/operation/bulkmerge">BulkMerge</a> and <a href="/operation/bulkupdate">BulkUpdate</a> operations, an implied logic and technique has been utilized.</p>

<p>Basically, a pseudo-temporary table will be created in the database under the transaction context. It then re-uses the <a href="/operation/bulkinsert">BulkInsert</a> operation to target that pseudo-temporary table. Through this technique, we brought all the data together from the client application into the database server (at one go).</p>

<p>You as a developer have the opportunity to maximize your own <code class="language-plaintext highlighter-rouge">qualifiers</code> by passing them as a list of <a href="/class/field">Field</a> objects. The library will then create a <code class="language-plaintext highlighter-rouge">CLUSTERED INDEX</code> on the pseudo-temporary table using your qualifiers.</p>

<blockquote>
  <p>If you have not passed any qualifiers, the primary key will be used by default. If the primary key is not present, it will use the identity field instead.</p>
</blockquote>

<p>Once all the data is in the database pseudo-temporary table, the correct SQL Statement will be used to cascade the changes towards the original table.</p>

<p>See the SQL Statements below.</p>

<h4 id="for-bulkdelete">For BulkDelete</h4>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">DELETE</span> <span class="n">T</span>
<span class="p">&gt;</span> <span class="n">FROM</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">OriginalTable</span><span class="p">]</span> <span class="n">T</span>
<span class="p">&gt;</span> <span class="n">INNER</span> <span class="n">JOIN</span> <span class="p">[</span><span class="n">PseudoTempTable</span><span class="p">]</span> <span class="n">TMP</span> <span class="n">ON</span> <span class="n">TMP</span><span class="p">.</span><span class="n">QualiferField1</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field1</span> <span class="n">AND</span> <span class="n">TMP</span><span class="p">.</span><span class="n">QualifierField2</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field2</span><span class="p">;</span>
</code></pre></div></div>

<h4 id="for-bulkmerge">For BulkMerge</h4>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">MERGE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">OriginalTable</span><span class="p">]</span> <span class="n">T</span>
<span class="p">&gt;</span> <span class="n">USING</span> <span class="p">[</span><span class="n">PseudoTempTable</span><span class="p">]</span> <span class="n">S</span> <span class="n">ON</span> <span class="n">S</span><span class="p">.</span><span class="n">QualiferField1</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field1</span> <span class="n">AND</span> <span class="n">S</span><span class="p">.</span><span class="n">QualifierField2</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field2</span>
<span class="p">&gt;</span> <span class="n">WHEN</span> <span class="n">NOT</span> <span class="n">MATCHED</span> <span class="n">THEN</span>
<span class="p">&gt;</span>      <span class="nf">INSERT</span> <span class="p">(...)</span> <span class="nf">VALUES</span> <span class="p">(...)</span>
<span class="p">&gt;</span> <span class="n">WHEN</span> <span class="n">MATCHED</span> <span class="n">THEN</span>
<span class="p">&gt;</span>     <span class="n">UPDATE</span>
<span class="p">&gt;</span>     <span class="nf">SET</span> <span class="p">(...);</span>
</code></pre></div></div>

<h4 id="for-bulkupdate">For BulkUpdate</h4>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">UPDATE</span> <span class="n">T</span>
<span class="p">&gt;</span> <span class="n">SET</span> <span class="n">T</span><span class="p">.</span><span class="n">Field3</span> <span class="p">=</span> <span class="n">TMP</span><span class="p">.</span><span class="n">Field3</span>
<span class="p">&gt;</span>     <span class="p">,</span> <span class="n">T</span><span class="p">.</span><span class="n">Field4</span> <span class="p">=</span> <span class="n">TMP</span><span class="p">.</span><span class="n">Field4</span>
<span class="p">&gt;</span>     <span class="p">,</span> <span class="p">...</span>
<span class="p">&gt;</span> <span class="n">FROM</span> <span class="p">[</span><span class="n">OriginalTable</span><span class="p">]</span> <span class="n">T</span>
<span class="p">&gt;</span> <span class="n">INNER</span> <span class="n">JOIN</span> <span class="p">[</span><span class="n">PseudoTempTable</span><span class="p">]</span> <span class="n">TMP</span> <span class="n">ON</span> <span class="n">TMP</span><span class="p">.</span><span class="n">QualiferField1</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field1</span> <span class="n">AND</span> <span class="n">TMP</span><span class="p">.</span><span class="n">QualifierField2</span> <span class="p">=</span> <span class="n">T</span><span class="p">.</span><span class="n">Field2</span><span class="p">;</span>
</code></pre></div></div>

<h4 id="the-following-objects-are-supported">The following objects are supported</h4>

<ul>
  <li>System.DataTable</li>
  <li>System.Data.Common.DbDataReader</li>
  <li>System.Collections.Generic.IEnumerable&lt;T&gt;</li>
</ul>

<h2 id="special-arguments">Special Arguments</h2>

<p>The arguments <code class="language-plaintext highlighter-rouge">qualifiers</code> and <code class="language-plaintext highlighter-rouge">usePhysicalPseudoTempTable</code> are provided for <a href="/operation/bulkdelete">BulkDelete</a>, <a href="/operation/bulkmerge">BulkMerge</a> and <a href="/operation/bulkupdate">BulkUpdate</a> operations.</p>

<p>The argument <code class="language-plaintext highlighter-rouge">qualifiers</code> is used to define the qualifier fields to be used in the operation. It usually refers to the <em>WHERE</em> expression of SQL Statements. If not given, the primary or identity column will be used.</p>

<p>The argument <code class="language-plaintext highlighter-rouge">usePhysicalPseudoTempTable</code> is used to define whether a physical pseudo-table will be created during the operation. By default, a temporary table (i.e.: #TableName) is used.</p>

<h2 id="caveats">Caveats</h2>

<p>RepoDB is automatically setting the value of the <code class="language-plaintext highlighter-rouge">options</code> argument to <code class="language-plaintext highlighter-rouge">SqlBulkCopyOptions.KeepIdentity</code> when calling the <a href="/operation/bulkdelete">BulkDelete</a>, <a href="/operation/bulkmerge">BulkMerge</a> and <a href="/operation/bulkupdate">BulkUpdate</a> if you have not passed any <code class="language-plaintext highlighter-rouge">qualifiers</code> and if your table has an IDENTITY primary key column. The same logic will apply if there is no primary key but has an IDENTITY column defined in the table.</p>

<p>In addition, when calling the <a href="/operation/bulkdelete">BulkDelete</a>, <a href="/operation/bulkmerge">BulkMerge</a> and <a href="/operation/bulkupdate">BulkUpdate</a> operations, the library is creating a pseudo temporary table behind the scene. It requires your user to have the correct privilege to <code class="language-plaintext highlighter-rouge">CREATE</code> a table in the database, otherwise a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlexception?view=dotnet-plat-ext-6.0">SqlException</a> will be thrown.</p>

<h2 id="get-started">Get Started</h2>

<p>To start with, simply install the library. At the Package Manager Console, type the command below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&gt;</span> <span class="n">Install</span><span class="p">-</span><span class="n">Package</span> <span class="n">RepoDb</span><span class="p">.</span><span class="n">SqlServer</span><span class="p">.</span><span class="n">BulkOperations</span>
</code></pre></div></div>

<blockquote>
  <p>You should install the version 1.0.4 (or above). Prior versions only support BulkInsert.</p>
</blockquote>

<p>Then, call the bootstrapper once.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SqlServerBootstrap</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">();</span>
</code></pre></div></div>

<p>After that, you can then start calling the Bulk Operations. See the sample code snippets below.</p>

<h3 id="bulkdelete">BulkDelete</h3>

<p>The code snippets below only showcase the <a href="/operation/bulkdelete">BulkDelete</a> via <code class="language-plaintext highlighter-rouge">System.Collections.Generic.IEnumerable&lt;T&gt;</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkDelete</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkDelete</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or with primary keys</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">primaryKeys</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="m">10045</span><span class="p">,</span> <span class="p">...,</span> <span class="m">11011</span> <span class="p">};</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkDelete</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">primaryKeys</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkDelete</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkDelete</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="bulkinsert">BulkInsert</h3>

<p>The code snippets below only showcase the <a href="/operation/bulkinsert">BulkInsert</a> via <code class="language-plaintext highlighter-rouge">System.Collections.Generic.IEnumerable&lt;T&gt;</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkInsert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkInsert</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="bulkmerge">BulkMerge</h3>

<p>The code snippets below only showcase the <a href="/operation/bulkmerge">BulkMerge</a> via <code class="language-plaintext highlighter-rouge">System.Collections.Generic.IEnumerable&lt;T&gt;</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkMerge</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkMerge</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkMerge</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkMerge</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="bulkupdate">BulkUpdate</h3>

<p>The code snippets below only showcase the <a href="/operation/bulkupdate">BulkUpdate</a> via <code class="language-plaintext highlighter-rouge">System.Collections.Generic.IEnumerable&lt;T&gt;</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkUpdate</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkUpdate</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkUpdate</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Or via table-name with qualifiers</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
	<span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GetCustomers</span><span class="p">();</span>
	<span class="kt">var</span> <span class="n">qualifiers</span> <span class="p">=</span> <span class="n">Field</span><span class="p">.</span><span class="nf">From</span><span class="p">(</span><span class="s">"LastName"</span><span class="p">,</span> <span class="s">"BirthDate"</span><span class="p">);</span>
	<span class="kt">var</span> <span class="n">rows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkUpdate</span><span class="p">(</span><span class="s">"Customer"</span><span class="p">,</span> <span class="n">customers</span><span class="p">,</span> <span class="n">qualifiers</span><span class="p">:</span> <span class="n">qualifiers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>As mentioned in the earlier section, both the <code class="language-plaintext highlighter-rouge">System.Data.Common.DbDataReader</code> and <code class="language-plaintext highlighter-rouge">System.DataTable</code> are supported.</p>
</blockquote>

<h2 id="when-to-use-the-batch-and-bulk-operations">When to use the Batch and Bulk Operations?</h2>

<p>Here, we can only advise based on our experience. To be honest, there is no standard of when to use what. It all depends on your situation (i.e.: Network Latency, Data, No. of Columns, etc).</p>

<p>The PROS of using Bulk are maximum performance. However, there are also CONS of usually using it. One of them is it keeps blocking the target table while under the Bulk operations transaction. It can however trigger (or also solve) a deadlock if not handled properly by the developers.</p>

<p>On our end, we usually use the Batch operations if the rows we are manipulating are less than or equal to <code class="language-plaintext highlighter-rouge">1000</code>. Beyond that, we standardize on using the Bulk operations.</p>

<h2 id="summary">Summary</h2>

<p>By using the <a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations">RepoDb.SqlServer.BulkOperations</a> features, you will have the following.</p>

<ul>
  <li>Maximizing the performance of your application when processing the large datasets.</li>
  <li>No need to write complex implementation of the BulkOperations. Every call is a single line of code.</li>
  <li>Handled by the OSS community, reviewed and used by others.</li>
  <li>Packed with high quality.</li>
  <li>Simple implementation. The code snippets are very easy to operate and maintain.</li>
</ul>

<hr />

<p>The original post was posted on <a href="https://dev.to/mikependon/c-bulk-operations-for-net-core-bulkdelete-bulkinsert-bulkmerge-bulkupdate-is-now-very-simple-with-repodb-orm-3can">DEV.to</a> by the author.</p>

<p>Thank you for reading this article.</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[We would like to share with you the latest and greatest updates of RepoDB ORM. Recently, we just published the complete out-of-the-box support of Bulk Operations for SQL Server in .NET data access space.]]></summary></entry><entry><title type="html">What will make you choose RepoDB over Dapper</title><link href="https://blogs.repodb.net/posts/2020/04/what-will-make-you-choose-repodb-over-dapper" rel="alternate" type="text/html" title="What will make you choose RepoDB over Dapper" /><published>2020-04-06T00:00:00+00:00</published><updated>2020-04-06T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/04/what-will-make-you-choose-repodb-over-dapper</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/04/what-will-make-you-choose-repodb-over-dapper"><![CDATA[<p>In this page, we will share with you the differences and what sets RepoDB apart from Dapper. We tried our best to make a 1-to-1 comparison for most areas. This page will hopefully help you decide as a developer to choose RepoDB as your micro-ORM (with a compelling reason).</p>

<p><em>“I am an open source contributor and I am here to share with you what I had done. I worked hard for it to improve the space of data access in .NET. I personally ask your support towards this library. I hope you share it, blog about it and use it.”</em></p>

<blockquote>
  <p>All the content of this tutorial is written by me (the author himself). Our knowledge of Dapper is not that deep when compared to our knowledge of RepoDb. So, please allow yourselves to <em>check</em> or <em>comment</em> right away if you think we made this page biased towards RepoDb.</p>
</blockquote>

<h3 id="before-we-begin">Before we begin</h3>

<p>The programming language and database provider we are using on our samples below are C# and SQL Server.</p>

<p>Both libraries are ORM frameworks for .NET. They are both lightweight, fast and efficient. Dapper is a full-fledged micro-ORM whereas RepoDB is a hybrid-ORM.</p>

<blockquote>
  <p>To avoid the bias on the comparison, we will not cover the features that are present in RepoDB but are absent in Dapper (i.e.: <code class="language-plaintext highlighter-rouge">Cache</code>, <code class="language-plaintext highlighter-rouge">Trace</code>, <code class="language-plaintext highlighter-rouge">Hints</code>, <code class="language-plaintext highlighter-rouge">Extensibility</code>, <code class="language-plaintext highlighter-rouge">StatementBuilder</code> and <code class="language-plaintext highlighter-rouge">Repositories</code>) (vice-versa). Also, the comparison does not include any other extension libraries of both (i.e.: <code class="language-plaintext highlighter-rouge">RepoDb.SqLite</code>, <code class="language-plaintext highlighter-rouge">RepoDb.MySql</code>, <code class="language-plaintext highlighter-rouge">RepoDb.PostgreSql</code>, <code class="language-plaintext highlighter-rouge">Dapper.Contrib</code>, <code class="language-plaintext highlighter-rouge">DapperExtensions</code>, <code class="language-plaintext highlighter-rouge">Dapper.SqlBuilder</code>, etc).</p>
</blockquote>

<h4 id="tables">Tables</h4>

<p>Let us assume we have the following database tables.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CREATE</span> <span class="n">TABLE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">Customer</span><span class="p">]</span>
<span class="p">(</span>
	<span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="n">BIGINT</span> <span class="nf">IDENTITY</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">)</span> 
	<span class="p">,</span> <span class="p">[</span><span class="n">Name</span><span class="p">]</span> <span class="nf">NVARCHAR</span><span class="p">(</span><span class="m">128</span><span class="p">)</span> <span class="n">NOT</span> <span class="n">NULL</span>
	<span class="p">,</span> <span class="p">[</span><span class="n">Address</span><span class="p">]</span> <span class="nf">NVARCHAR</span><span class="p">(</span><span class="n">MAX</span><span class="p">)</span>
	<span class="p">,</span> <span class="n">CONSTRAINT</span> <span class="p">[</span><span class="n">PK_Customer</span><span class="p">]</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="nf">CLUSTERED</span> <span class="p">([</span><span class="n">Id</span><span class="p">]</span> <span class="n">ASC</span> <span class="p">)</span>
<span class="p">)</span>
<span class="n">ON</span> <span class="p">[</span><span class="n">PRIMARY</span><span class="p">];</span>
<span class="n">GO</span>

<span class="n">CREATE</span> <span class="n">TABLE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">Product</span><span class="p">]</span>
<span class="p">(</span>
	<span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="n">BIGINT</span> <span class="nf">IDENTITY</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">)</span> 
	<span class="p">,</span> <span class="p">[</span><span class="n">Name</span><span class="p">]</span> <span class="nf">NVARCHAR</span><span class="p">(</span><span class="m">128</span><span class="p">)</span> <span class="n">NOT</span> <span class="n">NULL</span>
	<span class="p">,</span> <span class="p">[</span><span class="n">Price</span><span class="p">]</span> <span class="nf">Decimal</span><span class="p">(</span><span class="m">18</span><span class="p">,</span><span class="m">2</span><span class="p">)</span>
	<span class="p">,</span> <span class="n">CONSTRAINT</span> <span class="p">[</span><span class="n">PK_Product</span><span class="p">]</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="nf">CLUSTERED</span> <span class="p">([</span><span class="n">Id</span><span class="p">]</span> <span class="n">ASC</span> <span class="p">)</span>
<span class="p">)</span>
<span class="n">ON</span> <span class="p">[</span><span class="n">PRIMARY</span><span class="p">];</span>
<span class="n">GO</span>

<span class="n">CREATE</span> <span class="n">TABLE</span> <span class="p">[</span><span class="n">dbo</span><span class="p">].[</span><span class="n">Order</span><span class="p">]</span>
<span class="p">(</span>
	<span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="n">BIGINT</span> <span class="nf">IDENTITY</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">)</span> 
	<span class="p">,</span> <span class="p">[</span><span class="n">ProductId</span><span class="p">]</span> <span class="n">BIGINT</span> <span class="n">NOT</span> <span class="n">NULL</span>
	<span class="p">,</span> <span class="p">[</span><span class="n">CustomerId</span><span class="p">]</span> <span class="n">BIGINT</span>
	<span class="p">,</span> <span class="p">[</span><span class="n">OrderDateUtc</span><span class="p">]</span> <span class="nf">DATETIME</span><span class="p">(</span><span class="m">5</span><span class="p">)</span>
	<span class="p">,</span> <span class="p">[</span><span class="n">Quantity</span><span class="p">]</span> <span class="n">INT</span>
	<span class="p">,</span> <span class="n">CONSTRAINT</span> <span class="p">[</span><span class="n">PK_Order</span><span class="p">]</span> <span class="n">PRIMARY</span> <span class="n">KEY</span> <span class="nf">CLUSTERED</span> <span class="p">([</span><span class="n">Id</span><span class="p">]</span> <span class="n">ASC</span> <span class="p">)</span>
<span class="p">)</span>
<span class="n">ON</span> <span class="p">[</span><span class="n">PRIMARY</span><span class="p">];</span>
<span class="n">GO</span>
</code></pre></div></div>

<h4 id="models">Models</h4>

<p>Let us assume we have the following class models.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Customer</span>
<span class="p">{</span>
	<span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">string</span> <span class="n">Address</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">Product</span>
<span class="p">{</span>
	<span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">decimal</span> <span class="n">Price</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">Order</span>
<span class="p">{</span>
	<span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">long</span> <span class="n">ProductId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">long</span> <span class="n">CustomerId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="kt">int</span> <span class="n">Quantity</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
	<span class="k">public</span> <span class="n">DateTime</span> <span class="n">OrderDateUtc</span><span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="basic-crud-differences">Basic CRUD Differences</h3>

<h4 id="querying-multiple-rows">Querying multiple rows</h4>

<h4 id="dapper">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer];"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer];"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;();</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="querying-a-single-record">Querying a single record</h4>

<h4 id="dapper-1">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer] WHERE (Id = @Id);"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">}).</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-1">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer] WHERE (Id = @Id);"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">}).</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="m">10045</span><span class="p">).</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="inserting-a-record">Inserting a record</h4>

<h4 id="dapper-2">Dapper</h4>

<p>Execute:</p>

<p>By default, it returns the number of affected rows.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
    <span class="p">{</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address);"</span><span class="p">,</span> <span class="n">customer</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Query:</p>

<p>Returning the identity value.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
    <span class="p">{</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="s">"INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());"</span><span class="p">,</span> <span class="n">customer</span><span class="p">).</span><span class="nf">Single</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-2">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
    <span class="p">{</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteScalar</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="s">"INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());"</span><span class="p">,</span> <span class="n">customer</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
    <span class="p">{</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="p">(</span><span class="kt">long</span><span class="p">)</span><span class="n">connection</span><span class="p">.</span><span class="n">Insert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customer</span><span class="p">);</span> <span class="c1">// or connection.Insert&lt;Customer, long&gt;(customer);</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="updating-a-record">Updating a record</h4>

<h4 id="dapper-3">Dapper</h4>

<p>Execute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;"</span><span class="p">,</span>
    <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">,</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-3">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteScalar</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;(</span><span class="s">"UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;"</span><span class="p">,</span>
    <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">,</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Customer</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span><span class="p">,</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="s">"John Doe"</span><span class="p">,</span>
        <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span>
    <span class="p">};</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Update</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customer</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="deleting-a-record">Deleting a record</h4>

<h4 id="dapper-4">Dapper</h4>

<p>Execute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"DELETE FROM [dbo].[Customer] WHERE Id = @Id;"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-4">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteScalar</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;(</span><span class="s">"DELETE FROM [dbo].[Customer] WHERE Id = @Id;"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Delete</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="m">10045</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="advanced-calls-differences">Advanced Calls Differences</h3>

<h4 id="querying-a-parent-and-its-children">Querying a parent and its children</h4>

<p>Let us assume we have added the <code class="language-plaintext highlighter-rouge">Orders</code> (of type <code class="language-plaintext highlighter-rouge">IEnumerable&lt;Order&gt;)</code> property on our <code class="language-plaintext highlighter-rouge">Customer</code> class.</p>

<p>Customer:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Customer</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Address</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;</span> <span class="n">Orders</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Order:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Order</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">ProductId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">long</span> <span class="n">CustomerId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Quantity</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">DateTime</span> <span class="n">OrderDateUtc</span><span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="dapper-5">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT C.Id, C.Name, C.Address, O.ProductId, O.Quantity, O.OrderDateUtc FROM [dbo].[Customer] C INNER JOIN [dbo].[Order] O ON O.CustomerId = C.Id WHERE C.Id = @Id;"</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">,</span> <span class="n">Order</span><span class="p">,</span> <span class="n">Customer</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span>
    <span class="p">(</span><span class="n">customer</span><span class="p">,</span> <span class="n">order</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">??</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;();</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">order</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">customer</span><span class="p">;</span>
    <span class="p">},</span>
    <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>QueryMultiple:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT * FROM [dbo].[Customer] WHERE Id = @CustomerId; SELECT * FROM [dbo].[Order] WHERE CustomerId = @CustomerId;"</span><span class="p">;</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">QueryMultiple</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">CustomerId</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">}))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Read</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;().</span><span class="nf">First</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Read</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;().</span><span class="nf">ToList</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-5">RepoDB</h4>

<p>The <code class="language-plaintext highlighter-rouge">JOIN</code> feature is not being supported yet. However, there is an alternative way to do this in RepoDb. It can be done via <a href="/feature/multiplequery">multi-query</a> that executes packed <code class="language-plaintext highlighter-rouge">SELECT</code>-statements in a single call.</p>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT * FROM [dbo].[Customer] WHERE Id = @CustomerId; SELECT * FROM [dbo].[Order] WHERE CustomerId = @CustomerId;"</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">extractor</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">ExecuteQueryMultiple</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">CustomerId</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">extractor</span><span class="p">.</span><span class="n">Extract</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;().</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">extractor</span><span class="p">.</span><span class="n">Extract</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;().</span><span class="nf">AsList</span><span class="p">();</span>
    <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">orders</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customerId</span> <span class="p">=</span> <span class="m">10045</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">tuple</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryMultiple</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">,</span> <span class="n">Order</span><span class="p">&gt;(</span><span class="n">customer</span> <span class="p">=&gt;</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="n">customerId</span><span class="p">,</span> <span class="n">order</span> <span class="p">=&gt;</span> <span class="n">order</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">==</span> <span class="n">customerId</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">customer</span> <span class="p">=</span> <span class="n">tuple</span><span class="p">.</span><span class="n">Item1</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">tuple</span><span class="p">.</span><span class="n">Item2</span><span class="p">.</span><span class="nf">AsList</span><span class="p">();</span>
    <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">orders</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="querying-multiple-parent-and-their-children">Querying multiple parent and their children</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;();</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT C.Id, C.Name, C.Address, O.ProductId, O.Quantity, O.OrderDateUtc FROM [dbo].[Customer] C INNER JOIN [dbo].[Order] O ON O.CustomerId = C.Id;"</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">,</span> <span class="n">Order</span><span class="p">,</span> <span class="n">Customer</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span>
    <span class="p">(</span><span class="n">customer</span><span class="p">,</span> <span class="n">order</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">customer</span> <span class="p">=</span> <span class="n">customers</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span><span class="p">).</span><span class="nf">FirstOrDefault</span><span class="p">()</span> <span class="p">??</span> <span class="n">customer</span><span class="p">;</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">??</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;();</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">order</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">customer</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>QueryMultiple:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">"SELECT * FROM [dbo].[Customer]; SELECT * FROM [dbo].[Order];"</span><span class="p">;</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">QueryMultiple</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">CustomerId</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">}))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Read</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;().</span><span class="nf">ToList</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Read</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;().</span><span class="nf">ToList</span><span class="p">();</span>
        <span class="n">customers</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">customer</span> <span class="p">=&gt;</span>
            <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">orders</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">==</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span><span class="p">).</span><span class="nf">ToList</span><span class="p">());</span> <span class="c1">// Client memory processing</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-6">RepoDB</h4>

<p>Raw-SQL:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">extractor</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">ExecuteQueryMultiple</span><span class="p">(</span><span class="s">"SELECT * FROM [dbo].[Customer]; SELECT * FROM [dbo].[Order];"</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">extractor</span><span class="p">.</span><span class="n">Extract</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;().</span><span class="nf">AsList</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">extractor</span><span class="p">.</span><span class="n">Extract</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;().</span><span class="nf">AsList</span><span class="p">();</span>
    <span class="n">customers</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">customer</span> <span class="p">=&gt;</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">orders</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">==</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span><span class="p">).</span><span class="nf">AsList</span><span class="p">());</span> <span class="c1">// Client memory processing</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customerId</span> <span class="p">=</span> <span class="m">10045</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">tuple</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">QueryMultiple</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">,</span> <span class="n">Order</span><span class="p">&gt;(</span><span class="n">customer</span> <span class="p">=&gt;</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="n">customerId</span><span class="p">,</span> <span class="n">order</span> <span class="p">=&gt;</span> <span class="n">order</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">==</span> <span class="n">customerId</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">tuple</span><span class="p">.</span><span class="n">Item1</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="n">tuple</span><span class="p">.</span><span class="n">Item2</span><span class="p">.</span><span class="nf">AsList</span><span class="p">();</span>
    <span class="n">customers</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">customer</span> <span class="p">=&gt;</span>
        <span class="n">customer</span><span class="p">.</span><span class="n">Orders</span> <span class="p">=</span> <span class="n">orders</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">==</span> <span class="n">customer</span><span class="p">.</span><span class="n">Id</span><span class="p">).</span><span class="nf">AsList</span><span class="p">());</span> <span class="c1">// Client memory processing</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="inserting-multiple-rows">Inserting multiple rows</h4>

<h4 id="dapper-6">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">identities</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="s">"INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Actually, this is not clear to me:</strong></p>

<ul>
  <li>Is it creating an implicit transaction? What if one row fails?</li>
  <li>Is it iterating the list and call the <code class="language-plaintext highlighter-rouge">DbCommand.Execute&lt;Method&gt;</code> multiple times?</li>
</ul>

<p>Please correct me here so I can update this page right away.</p>

<h4 id="repodb-7">RepoDB</h4>

<p>Batch operation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">InsertAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above operation can be batched by passing a value on the <code class="language-plaintext highlighter-rouge">batchSize</code> argument.</p>

<p><strong>Note:</strong> You can target a specific column. In addition, the <code class="language-plaintext highlighter-rouge">identity</code> values are automatically set back to the entities.</p>

<p>Bulk operation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkInsert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above operation can be batched by passing a value on the <code class="language-plaintext highlighter-rouge">batchSize</code> argument.</p>

<p><strong>Note:</strong> This is just an FYI. The operation is using the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopy?view=dotnet-plat-ext-7.0">SqlBulkCopy</a> of ADO.Net. This should not be compared to Dapper’s performance due to the fact that this is a real bulk-operation. This is far faster (extremely fast) when compared to both Dapper (multi-inserts) and RepoDB (<code class="language-plaintext highlighter-rouge">InsertAll</code>) operations.</p>

<h4 id="merging-multiple-rows">Merging multiple rows</h4>

<h4 id="dapper-7">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">@"MERGE [dbo].[Customer] AS T
        USING
            (SELECT @Name, @Address) AS S
        ON
            S.Id = T.Id
        WHEN NOT MATCH THEN
            INSERT INTO
            (
                Name
                , Address
            )
            VALUES
            (
                S.Name
                , S.
            Address)
        WHEN MATCHED THEN
            UPDATE
            SET Name = S.Name
                , Address = S.Address
        OUTPUT INSERTED.Id AS Result;"</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">identities</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here, I have the same question as the previous section.</p>

<h4 id="repodb-8">RepoDB</h4>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">MergeAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above operation can be batched by passing a value on the <code class="language-plaintext highlighter-rouge">batchSize</code> argument.</p>

<p><strong>Note:</strong> You can set the qualifier fields. In addition, the <code class="language-plaintext highlighter-rouge">identity</code> values are automatically set back to the entities for the newly inserted records.</p>

<h4 id="updating-multiple-rows">Updating multiple rows</h4>

<h4 id="dapper-8">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"UPDATE [dbo].[Customer] SET Name = @Name, Address = @Address WHERE Id = @Id;"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-9">RepoDB</h4>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">UpdateAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above operation can be batched by passing a value on the <code class="language-plaintext highlighter-rouge">batchSize</code> argument.</p>

<p><strong>Note:</strong> You can set the qualifier fields.</p>

<h4 id="bulk-inserting-multiple-rows">Bulk-inserting multiple rows</h4>

<h4 id="dapper-9">Dapper</h4>

<p>ADO.NET:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">table</span> <span class="p">=</span> <span class="nf">ConvertToTable</span><span class="p">(</span><span class="n">customers</span><span class="p">);</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sqlBulkCopy</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlBulkCopy</span><span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">transaction</span><span class="p">))</span>
        <span class="p">{</span>
        <span class="n">sqlBulkCopy</span><span class="p">.</span><span class="n">DestinationTableName</span> <span class="p">=</span> <span class="s">"Customer"</span><span class="p">;</span>
        <span class="n">sqlBulkCopy</span><span class="p">.</span><span class="nf">WriteToServer</span><span class="p">(</span><span class="n">table</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Note:</strong> You can as well pass an instance of <a href="https://learn.microsoft.com/en-us/dotnet/api/system.data.common.dbdatareader?view=net-6.0">DbDataReader</a> (instead of <code class="language-plaintext highlighter-rouge">DataTable</code>).</p>

<h4 id="repodb-10">RepoDB</h4>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BulkInsert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Note:</strong> You can as well pass an instance of <a href="https://learn.microsoft.com/en-us/dotnet/api/system.data.common.dbdatareader?view=net-6.0">DbDataReader</a>.</p>

<ul>
  <li>Fluent (Targeted):</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="nf">GenerateCustomers</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="nf">BulkInsert</span><span class="p">(</span><span class="s">"[dbo].[Customer]"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="querying-the-rows-by-batch">Querying the rows by batch</h4>

<h4 id="dapper-10">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="s">@"WITH CTE AS
        (
            SELECT TOP (@Rows) ROW_NUMBER() OVER(ORDER BY Name ASC) AS RowNumber
            FROM [dbo].[Customer]
            WHERE (Address = @Address)
        )
        SELECT Id
            , Name
            , Address
        FROM
            CTE
        WHERE
            RowNumber BETWEEN @From AND (@From + @Rows);"</span><span class="p">;</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">From</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">Rows</span> <span class="p">=</span> <span class="m">100</span><span class="p">,</span> <span class="n">Address</span> <span class="p">=</span> <span class="s">"New York"</span> <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Note:</strong> You can as well execute it via (LIMIT) keyword. It is on your preference.</p>

<h4 id="repodb-11">RepoDB</h4>

<p>Fluent:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">BatchQuery</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Address</span> <span class="p">==</span> <span class="s">"New York"</span><span class="p">,</span>
        <span class="n">page</span><span class="p">:</span> <span class="m">0</span><span class="p">,</span>
        <span class="n">rowsPerBatch</span><span class="p">:</span> <span class="m">100</span><span class="p">,</span>
        <span class="n">orderBy</span><span class="p">:</span> <span class="n">OrderField</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Name</span> <span class="p">=</span> <span class="n">Order</span><span class="p">.</span><span class="n">Ascending</span> <span class="p">}));</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="replicate-records-from-different-database">Replicate records from different database</h4>

<h4 id="dapper-11">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">SourceConnectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer];"</span><span class="p">);</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">DestinationConnectionString</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">identities</span> <span class="p">=</span> <span class="n">destinationConnection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;(</span><span class="s">"INSERT INTO [dbo].[Customer] (Name, Address) VALUES (@Name, @Address); SELECT CONVERT(BIGINT, SCOPE_IDENTITY());"</span><span class="p">,</span> <span class="n">customers</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-12">RepoDB</h4>

<p>Fluent (<a href="/operation/insertall">InsertAll</a>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">SourceConnectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;();</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">DestinationConnectionString</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">destinationConnection</span><span class="p">.</span><span class="n">InsertAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent (<a href="/operation/bulkinsert">BulkInsert</a>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">SourceConnectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="n">QueryAll</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;();</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">DestinationConnectionString</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">destinationConnection</span><span class="p">.</span><span class="n">BulkInsert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">customers</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fluent (Streaming):</p>

<p>This is the most optimal and recommended call for large datasets. We do not bring the data as class objects in the client application.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">sourceConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">SourceConnectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">reader</span> <span class="p">=</span> <span class="n">sourceConnection</span><span class="p">.</span><span class="nf">ExecuteReader</span><span class="p">(</span><span class="s">"SELECT * FROM [dbo].[Customer];"</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">destinationConnection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">DestinationConnectionString</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">affectedRows</span> <span class="p">=</span> <span class="n">destinationConnection</span><span class="p">.</span><span class="n">BulkInsert</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">reader</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Note:</strong> Check for collation constraints. It is an ADO.NET thing.</p>

<h3 id="passing-of-parameters">Passing of Parameters</h3>

<h4 id="dapper-12">Dapper</h4>

<p>Dynamic:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
</code></pre></div></div>

<p>It is always an <code class="language-plaintext highlighter-rouge">Equal</code> operation. You control the query through SQL Statement.</p>

<p>Dynamic Parameters:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">parameters</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DynamicParameters</span><span class="p">();</span>
<span class="n">parameters</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="s">"John Doe"</span><span class="p">);</span>
<span class="n">parameters</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"Address"</span><span class="p">,</span> <span class="s">"New York"</span><span class="p">);</span>
<span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="n">parameters</span><span class="p">);</span>
</code></pre></div></div>

<h4 id="repodb-13">RepoDB</h4>

<p>Dynamic:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">10045</span> <span class="p">});</span>
</code></pre></div></div>

<p>Same as Dapper, it is always referring to an <code class="language-plaintext highlighter-rouge">Equal</code> operation. You control the query through SQL Statement.</p>

<p>Linq Expression:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="m">10045</span><span class="p">);</span>
</code></pre></div></div>

<p>QueryField:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">new</span> <span class="nf">QueryField</span><span class="p">(</span><span class="s">"Id"</span><span class="p">,</span> <span class="m">10045</span><span class="p">));</span>
</code></pre></div></div>

<p>QueryField(s) or QueryGroup:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">queryFields</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
<span class="p">{</span>
    <span class="k">new</span> <span class="nf">QueryField</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="s">"John Doe"</span><span class="p">)</span>
    <span class="k">new</span> <span class="nf">QueryField</span><span class="p">(</span><span class="s">"Address"</span><span class="p">,</span> <span class="s">"New York"</span><span class="p">)</span>
<span class="p">};</span>
<span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">queryFields</span><span class="p">);</span> <span class="c1">// or Query&lt;T&gt;(new QueryGroup(queryFields));</span>
</code></pre></div></div>

<h3 id="array-of-parameters">Array of Parameters</h3>

<h4 id="dapper-13">Dapper</h4>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">addresses</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="s">"New York"</span><span class="p">,</span> <span class="s">"Washington"</span> <span class="p">};</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer] WHERE Address IN (@Addresses);"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Addresses</span> <span class="p">=</span> <span class="n">addresses</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="repodb-14">RepoDB</h4>

<p>ExecuteQuery:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">addresses</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="s">"New York"</span><span class="p">,</span> <span class="s">"Washington"</span> <span class="p">};</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">ExecuteQuery</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="s">"SELECT * FROM [dbo].[Customer] WHERE Address IN (@Addresses);"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Addresses</span> <span class="p">=</span> <span class="n">addresses</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>For further explanation, you can visit our <a href="https://repodb.readthedocs.io/en/latest/pages/rawsql.html#array-values">documentation</a>.</p>

<p>Query:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SqlConnection</span><span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">addresses</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="s">"New York"</span><span class="p">,</span> <span class="s">"Washington"</span> <span class="p">};</span>
    <span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">connection</span><span class="p">.</span><span class="n">Query</span><span class="p">&lt;</span><span class="n">Customer</span><span class="p">&gt;(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">addresses</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">Address</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="expression-trees">Expression Trees</h3>

<ul>
  <li>Dapper does not support <code class="language-plaintext highlighter-rouge">Linq Expressions</code>, only <code class="language-plaintext highlighter-rouge">Dynamics</code> and <code class="language-plaintext highlighter-rouge">DynamicParameters</code>.</li>
  <li>RepoDB supports <code class="language-plaintext highlighter-rouge">Linq Expressions</code>, <code class="language-plaintext highlighter-rouge">Dynamics</code> and <code class="language-plaintext highlighter-rouge">QueryObjects</code>.</li>
</ul>

<p><strong>Note:</strong> The <code class="language-plaintext highlighter-rouge">DynamicParameters</code> is just a subset of <code class="language-plaintext highlighter-rouge">QueryObjects</code>. The <code class="language-plaintext highlighter-rouge">QueryObjects</code> has much more capability that can further support the <code class="language-plaintext highlighter-rouge">Linq Expressions</code>.</p>

<p>Please visit both documentation pages.</p>

<ul>
  <li><a href="https://dapper-tutorial.net/parameter-dynamic">Dapper</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/wiki/Expression-Trees">RepoDB</a></li>
</ul>

<h3 id="supported-databases">Supported Databases</h3>

<h4 id="dapper-14">Dapper</h4>

<p>Supports all RDBMS data providers.</p>

<h4 id="repodb-15">RepoDB</h4>

<ol>
  <li>Raw-SQLs support all RDBMS data providers.</li>
  <li>Fluent calls only support SQL Server, SqLite, MySql and PostgreSql.</li>
</ol>

<h3 id="performance-and-efficiency">Performance and Efficiency</h3>

<p>We only refer to one of the community-approved ORM bencher, the <a href="https://github.com/FransBouma/RawDataAccessBencher">RawDataAccessBencher</a>.</p>

<p><strong>Net Core:</strong></p>

<p>Here is our observation from the official execution results. The official result can be found <a href="https://github.com/FransBouma/RawDataAccessBencher/blob/master/Results/20190520_netcore.txt">here</a>.</p>

<p>Performance:</p>

<ul>
  <li>RepoDB is the fastest ORM when fetching set-records. Both raw-SQL and fluent calls.</li>
  <li>Dapper and RepoDB speed is identical when fetching single-record.</li>
  <li>Dapper is faster than RepoDB’s fluent calls when fetching single-record.</li>
</ul>

<p>Efficiency:</p>

<ul>
  <li>RepoDB is the most-efficient ORM when fetching set-records. Both raw-SQL and fluent calls.</li>
  <li>Dapper is much more efficient than RepoDB when fetching single-record.</li>
</ul>

<p><strong>NetFramework:</strong></p>

<p>RepoDB is the fastest and the most-efficient ORM for fetching both single and set records. The official results can be found <a href="https://github.com/FransBouma/RawDataAccessBencher/blob/master/Results/20190520_netfx.txt">here</a>.</p>

<h3 id="quality">Quality</h3>

<h4 id="dapper-15">Dapper</h4>

<p>Dapper has already been running since 2012 and is being used by <a href="https://stackoverflow.com">StackOverflow.com</a>. It has a huge consumer base and is hugely backed by the community.</p>

<h4 id="repodb-16">RepoDB</h4>

<p>We did our best to write one-test per scenario and we have delivered thousands of items (approximately 8K) for both <code class="language-plaintext highlighter-rouge">Unit</code> and <code class="language-plaintext highlighter-rouge">Integration</code> tests. We would like your help to review them as well.</p>

<p>Below are the links to our test suites.</p>

<ul>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests">Core Unit Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests">Core Integration Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.SqlServer/RepoDb.SqlServer.UnitTests">SqlServer Unit Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.SqlServer/RepoDb.SqlServer.IntegrationTests">SqlServer Integration Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.SqLite/RepoDb.SqLite.UnitTests">SqLite Unit Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.SqLite/RepoDb.SqLite.IntegrationTests">SqLite Integration Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.MySql/RepoDb.MySql.UnitTests">MySql Unit Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.MySql/RepoDb.MySql.IntegrationTests">MySql Integration Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.PostgreSql/RepoDb.PostgreSql.UnitTests">PostgreSql Unit Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.PostgreSql/RepoDb.PostgreSql.IntegrationTests">PostgreSql Integration Tests</a></li>
  <li><a href="https://github.com/mikependon/RepoDb/tree/master/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests">RepoDb.SqlServer.BulkOperations Integration Tests</a></li>
</ul>

<blockquote>
  <p>We (or I as an author) have been challenged that the quality of the software does not depend on the number of tests. However, we strongly believe that spending much effort on writing a test will give confidence to the library consumers (i.e.: .NET community). Practically, it helps us to avoid manual revisits on the already-working features if somebody is doing a PR to us; it prevents the library from any surprising bugs.</p>
</blockquote>

<h4 id="conclusion-to-the-quality">Conclusion to the Quality</h4>

<p>Both are of high quality but Dapper is far more mature than RepoDb. We will not contest this!</p>

<h3 id="library-support">Library Support</h3>

<h4 id="dapper-16">Dapper</h4>

<p>Proven and is backed hugely by the .NET Community; funded by <a href="https://stackoverflow.com">StackOverflow.com</a>.</p>

<h4 id="repodb-17">RepoDB</h4>

<p>Backed by one person and is not funded nor sponsored by any entity. Just starting to expand and asking for more support from the .NET Community.</p>

<h3 id="licensing-and-legality">Licensing and Legality</h3>

<p>Both are under the <a href="http://apache.org/licenses/LICENSE-2.0.html">Apache-2.0</a> license.</p>

<h4 id="disclaimer">Disclaimer</h4>

<p>We are not experts in legal matters but we are consulting. If any conflict arises regarding the copyright or trademark in front of RepoDB, then that is not yet addressed.</p>

<hr />

<h3 id="overall-conclusion">Overall Conclusion</h3>

<p>We hope that you somehow consider and revisit this library. It has improved a lot from where it has started.</p>

<h4 id="simplicity">Simplicity</h4>

<p>Dapper is lightweight but will drag you to the most complex level of code development. It is always tedious to write raw-SQLs and it is hard to maintain due to the fact that it is not compiler-friendly. In addition, to accomplish a necessary task, you need to implement necessary features.</p>

<p>RepoDB is a very easy-to-use ORM with enough feature sets that you can play on.</p>

<h4 id="performance">Performance</h4>

<p>RepoDB is faster than Dapper, enough reason to choose this library if the only factor is performance.</p>

<blockquote>
  <p>RepoDB is the fastest ORM in .NET. This claim is supported by the official run of the community-approved ORM bencher <a href="https://github.com/FransBouma/RawDataAccessBencher">RawDataAccessBencher</a>.</p>
</blockquote>

<h4 id="efficiency">Efficiency</h4>

<p>RepoDB is more efficient than Dapper (same claim as in Performance).</p>

<h4 id="experience">Experience</h4>

<p>It is easier and faster to develop the code snippets with RepoDb. It has a rich feature set which can be used right away (i.e.: 2nd-Layer Cache, Fluent Methods). It will help you as a developer deliver more code snippets in a fast and clean manner.</p>

<h4 id="features">Features</h4>

<p>In RepoDB, having the necessary features within the space of a micro-ORM will help you a lot in your development.</p>

<p>Features like <code class="language-plaintext highlighter-rouge">Bulk</code> &amp; <code class="language-plaintext highlighter-rouge">Batch</code> operations, <code class="language-plaintext highlighter-rouge">PropertyHandlers</code>, <code class="language-plaintext highlighter-rouge">2nd-Level Cache</code>, <code class="language-plaintext highlighter-rouge">Expression Trees</code>, <code class="language-plaintext highlighter-rouge">Multi Queries</code> and inline <code class="language-plaintext highlighter-rouge">Hints</code> are the most commonly used features. The major pain point is that it is absent in Dapper.</p>

<hr />

<p>The original post was posted on <a href="https://dev.to/mikependon/c-what-will-make-you-choose-repodb-over-dapper-orm-3eb8">DEV.to</a> by the author.</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[In this page, we will share with you the differences and what sets RepoDB apart from Dapper. We tried our best to make a 1-to-1 comparison for most areas. This page will hopefully help you decide as a developer to choose RepoDB as your micro-ORM (with a compelling reason).]]></summary></entry><entry><title type="html">Happy 2nd Year Anniversary</title><link href="https://blogs.repodb.net/posts/2020/04/happy-2nd-year-anniversary" rel="alternate" type="text/html" title="Happy 2nd Year Anniversary" /><published>2020-04-02T00:00:00+00:00</published><updated>2020-04-02T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/04/happy-2nd-year-anniversary</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/04/happy-2nd-year-anniversary"><![CDATA[<p>It was 2 years ago when the <a href="https://www.nuget.org/packages/RepoDb/1.0.0">first version</a> release of <a href="https://github.com/mikependon/RepoDb">RepoDB</a> was placed at <a href="https://www.nuget.org/packages/RepoDb">Nuget.org</a>.</p>

<h3 id="story">Story</h3>

<p>I started writing the first code last March 15, 2018. The first official class that has been written is <a href="/https://repodb.net/class/baserepository">BaseRepository</a>. I developed the initial compiler via <code class="language-plaintext highlighter-rouge">IL</code> and found it extremely fast. By that time, I was obsessed with beating Dapper ORM when it comes to performance. I first wrote the following methods (<a href="/https://repodb.net/operation/executequery">ExecuteQuery</a>, <a href="/https://repodb.net/operation/executenonquery">ExecuteNonQuery</a>, <a href="/https://repodb.net/operation/executescalar">ExecuteScalar</a> and <a href="/https://repodb.net/operation/executescalar">ExecuteReader</a>). Then, I added some basic methods like (<a href="/https://repodb.net/operation/insert">Insert</a>, <a href="/https://repodb.net/operation/delete">Delete</a>, <a href="/https://repodb.net/operation/update">Update</a> and <a href="/https://repodb.net/operation/query">Query</a>). The implementation is very shallow and NOT-tested.</p>

<blockquote>
  <p>The IL code can be found <a href="https://github.com/mikependon/RepoDb/blob/master/RepoDb.Core/RepoDb/Reflection/DelegateFactory.cs">here</a>, but it is not being used by the library now. We are now using the <code class="language-plaintext highlighter-rouge">Linq-Based</code> compiler (can be found <a href="https://github.com/mikependon/RepoDb/blob/master/RepoDb.Core/RepoDb/Reflection/FunctionFactory.cs">here</a>).</p>
</blockquote>

<p>The next day, I came to the office early and checked in the RepoDB code snippets in our internal repository. A few minutes after, I broadcasted an email to all the developers of Orsted A/S at Kuala Lumpur, Malaysia without knowing the effect of it.</p>

<p>I received much criticism from various architects the same day (i.e.: re-inventing the wheel, too ambitious, etc).</p>

<p>However, I got good feedback from my direct Team Lead.</p>

<h3 id="motivations">Motivations</h3>

<p>As a leading developer of the team by that time, we needed to deliver a solution that will calculate the power production in a real-time manner. I initially developed the solution by reusing the repository-based implementation of our existing project (using the Dapper ORM). I found it hard to develop a very dynamic repository like what <a href="/https://repodb.net/class/baserepository">BaseRepository</a> and <a href="/https://repodb.net/class/dbrepository">DbRepository</a> can do now. I also encountered a lot of problems when using the <code class="language-plaintext highlighter-rouge">Dynamics</code> and <a href="https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0">ExpandoObject</a>. I gave up when I needed to read data from a <code class="language-plaintext highlighter-rouge">View</code> with a different <code class="language-plaintext highlighter-rouge">ColumnName</code> as the primary key.</p>

<p>TBH, I am also very good at ADO.NET by mastering it since the start of my career 13 years ago (from today). I also have experience building CRM solutions that have a feature called <code class="language-plaintext highlighter-rouge">Selection-Wizard</code> which allows the user to pre-select the columns they would like to query from the complex relationships of the CRM, and provide reports on top of it. I know that I am capable of creating an ORM and with great motivation for new things to play with.</p>

<h3 id="reddit">Reddit</h3>

<p>I first posted RepoDB on Reddit 2 years ago. The first post was titled <strong>RepoDB - a very fast lightweight ORM and has the perfect spices of Micro-ORM. Faster than Dapper! Rooting for the experts about this.</strong>, and the post can be found <a href="https://www.reddit.com/r/csharp/comments/8y5pm3/repodb_a_very_fast_lightweight_orm_and_has_the/">here</a>.</p>

<p>A lot of people joined the discussion and the thread topped the <code class="language-plaintext highlighter-rouge">r/csharp</code> in just a few minutes. I saw a lot of up/down votes and some frustrations from the community. Honestly, I do not know how to diligently answer the questions from the community, could be the reason for the frustrations.</p>

<p>I remember one comment that brought me to <a href="https://github.com/FransBouma/RawDataAccessBencher">RawDataAccessBencher</a> ORM bencher of FransBouma. He wanted me to test the library there. The result was that RepoDB was the second slowest ORM and I was totally shocked, actually. I know that the IL I developed is very fast, but by that time, it was only very fast for extracting millions of rows (in a single iteration) (maybe the fastest), but is very slow if you bench it with its execution mean-deviation (includes multiple iterations by batch).</p>

<p>I analyzed the culprits in the code snippets and also tried to optimize the IL. I solved the problem and brought RepoDB as the fastest ORM a month after. The official technique was posted by me on my old blog (can be found <a href="https://codesdirectory.blogspot.com/2018/09/repodb-net-lightweight-orm-library.html">here</a>).</p>

<p>It was also 2 years ago (4 months after pushing the first version) that RepoDB was officially accepted by FransBouma to be a part of the <a href="https://github.com/FransBouma/RawDataAccessBencher">RawDataAccessBencher</a> ORM bencher. That is amazing and gave me more spirit to further develop the lib</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="repodb" /><summary type="html"><![CDATA[It was 2 years ago when the first version release of RepoDB was placed at Nuget.org.]]></summary></entry><entry><title type="html">Adding more contents to RepoDB.NET</title><link href="https://blogs.repodb.net/posts/2020/03/adding-more-contents-to-repodb-net" rel="alternate" type="text/html" title="Adding more contents to RepoDB.NET" /><published>2020-03-16T00:00:00+00:00</published><updated>2020-03-16T00:00:00+00:00</updated><id>https://blogs.repodb.net/posts/2020/03/adding-more-contents-to-repodb-net</id><content type="html" xml:base="https://blogs.repodb.net/posts/2020/03/adding-more-contents-to-repodb-net"><![CDATA[<p>As of writing this, I am busy working on the <a href="http://repodb.net">RepoDB.NET</a> site, providing content to each page.</p>

<p>The <a href="/docs">docs</a> page has been introduced with the following sections.</p>

<ul>
  <li><a href="/docs#get-started">Get Started</a></li>
  <li><a href="/docs#features">Features</a></li>
  <li><a href="/docs#operations">Operations</a></li>
  <li><a href="/docs#classes">Classes</a></li>
  <li><a href="/docs#attributes">Attributes</a></li>
  <li><a href="/docs#enumerations">Enumerations</a></li>
  <li><a href="/docs#interfaces">Interfaces</a></li>
  <li><a href="/docs#cachers">Cachers</a></li>
  <li><a href="/docs#mappers">Mappers</a></li>
  <li><a href="/docs#extensibilities">Extensibilities</a></li>
</ul>

<p>The links have been provided but there is no content yet on the pages, but the initial version of our <a href="/about">about</a> page has also been introduced.</p>

<p>Lastly, the design of the site has already been put in place (header, footer, footer-links an</p>]]></content><author><name>RepoDB</name><email>michael.c.pendon@outlook.com</email></author><category term="blogs" /><category term="update" /><summary type="html"><![CDATA[As of writing this, I am busy working on the RepoDB.NET site, providing content to each page.]]></summary></entry></feed>