remove sql databases lecture

- lecture moved to webdev-basics
- update link to sql database lecture
- also update links to http and rest lectures
- update readme
main
borb 3 weeks ago
parent cc239a6c58
commit bb1f5fe3ad

@ -13,10 +13,10 @@
/* buutti.css */
/* @theme buutti */div#\:\$p>svg>foreignObject>section .columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns12{display:grid;grid-template-columns:1fr 2fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns21{display:grid;grid-template-columns:2fr 1fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns32{display:grid;grid-template-columns:3fr 2fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns23{display:grid;grid-template-columns:2fr 3fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns111{display:grid;grid-template-columns:1fr 1fr 1fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .centered{display:flex;flex-direction:column;justify-content:center;text-align:center}div#\:\$p>svg>foreignObject>section .tableborderless td,div#\:\$p>svg>foreignObject>section th{border:none!important;border-collapse:collapse}div#\:\$p>svg>foreignObject>section.extra{background-color:#5d275d;background-image:linear-gradient(to bottom,#401a40,#1d0c1d);color:white}div#\:\$p>svg>foreignObject>section.extra a{color:rgb(145,255,209)}div#\:\$p>svg>foreignObject>section.exercise{background-color:#29366f;background-image:linear-gradient(to bottom,#20636a,#173742);color:white}div#\:\$p>svg>foreignObject>section.exercise a{color:rgb(211,173,255)}
/* @theme 3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9 */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="1" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
/* @theme lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5 */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="1" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h1 id="restful-http-methods">RESTful HTTP Methods</h1>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="2" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="2" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="contents">Contents</h2>
<ul>
<li><a href="#http-methods-for-restful-apis">HTTP methods for RESTful APIs</a></li>
@ -26,16 +26,16 @@
<li><a href="#http-patch-method">HTTP <code>PATCH</code> method</a></li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="3" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="3" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="http-methods-for-restful-apis">HTTP methods for RESTful APIs</h2>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-marpit-fragments="8" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="4" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-marpit-fragments="8" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="4" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="restful-api">RESTful API</h3>
<ul>
<li data-marpit-fragment="1">We'll be extending our Web API into a full-blown <em><strong>RESTful API</strong></em>
<ul>
<li data-marpit-fragment="2">More about REST in <a href="https://gitea.buutti.com/education/frontend-basics/src/branch/main/3-rest-architecture.md">Frontend Basics Lecture 3: REST Architecture</a></li>
<li data-marpit-fragment="3">A good idea to also check out <a href="https://gitea.buutti.com/education/frontend-basics/src/branch/main/2-http.md">Frontend Basics Lecture 2: HTTP methods</a></li>
<li data-marpit-fragment="2">It's a good idea to check out <a href="https://gitea.buutti.com/education/webdev-basics/src/branch/main/http.md">Webdev Basics: HTTP methods</a> first</li>
<li data-marpit-fragment="3">Also, some ramblings about REST in <a href="https://gitea.buutti.com/education/webdev-basics/src/branch/main/rest-architecture.md">Webdev Basics: REST Architecture</a></li>
</ul>
</li>
<li data-marpit-fragment="4">We have so far implemented <code>GET</code> and <code>POST</code> methods for reading resources from the API and creating new ones to it, respectively</li>
@ -51,7 +51,7 @@
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="5" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="5" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="primary-http-request-methods">Primary HTTP request methods</h3>
<p>The primary HTTP request methods with descriptions:</p>
<table>
@ -92,10 +92,10 @@
</table>
<p><a href="https://www.restapitutorial.com/lessons/httpmethods.html">https://www.restapitutorial.com/lessons/httpmethods.html</a></p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="6" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="6" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="http-post-method">HTTP <code>POST</code> method</h2>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="7" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="7" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="handling-httppost-requests">Handling <code>HttpPost</code> Requests</h3>
<ul>
<li data-marpit-fragment="1">Remember that HTTP requests can include a content body</li>
@ -111,7 +111,7 @@
<li data-marpit-fragment="4">However, nothing prevents you from using a custom type variable</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="8" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="8" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<ul>
<li data-marpit-fragment="1">ASP.NET deserializes the request content body into an object:<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-comment">// Models/Contact.cs</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Contact</span>
@ -134,10 +134,10 @@
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="9" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="9" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="creating-a-post-request-with-postman">Creating a POST Request with Postman</h3>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="10" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="10" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h4 id="request-headers">Request headers</h4>
<ul>
<li data-marpit-fragment="1">ASP.NET knows to deserialize the content if the content type is set to JSON in the HTTP requests <em><strong>headers</strong></em>
@ -152,7 +152,7 @@
<p><img src="imgs/5-rest-architecture_1.png" alt="" style="width:800px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="11" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="11" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h4 id="request-body">Request body</h4>
<p>After setting the header,</p>
<ol>
@ -165,7 +165,7 @@
<p><img src="imgs/5-rest-architecture_2.png" alt="" style="width:800px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="12" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="12" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h4 id="sending-the-request">Sending the request</h4>
<ul>
<li data-marpit-fragment="1">If the <code>POST</code> method is routed at <code>http://localhost:54106/api/contacts</code>:</li>
@ -174,7 +174,7 @@
<p><img src="imgs/5-rest-architecture_3.png" alt="" style="width:800px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-marpit-fragments="1" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="exercise invert" data-marpit-pagination="13" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-marpit-fragments="1" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="exercise invert" data-marpit-pagination="13" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="exercise-1-creating-a-post-endpoint">Exercise 1: Creating a <code>POST</code> Endpoint</h3>
<p>Continue working on the CourseAPI.</p>
@ -183,7 +183,7 @@
<img src="imgs/5-rest-architecture_4.png" alt="" /></li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="14" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="14" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="http-put-method">HTTP <code>PUT</code> method</h2>
<ul>
<li data-marpit-fragment="1">Use <code>PUT</code> to replace an existing resource, e.g. an element in a list, with a new one</li>
@ -194,7 +194,7 @@
<p><img src="imgs/5-rest-architecture_5.png" alt="" style="width:900px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="15" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="15" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="handling-httpput-requests">Handling <code>HttpPut</code> requests</h3>
<ul>
<li data-marpit-fragment="1">The ID is fetched from the URI and the contents from the request body</li>
@ -211,7 +211,7 @@
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="16" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="16" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="exercise-2-creating-a-put-endpoint">Exercise 2: Creating a <code>PUT</code> Endpoint</h3>
<ul>
<li data-marpit-fragment="1">In CoursesController class, create a method for PUT requests with the URI api/courses/{id}
@ -225,7 +225,7 @@
<li data-marpit-fragment="6">Test with Swagger/Postman</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="17" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="17" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="http-delete-method">HTTP <code>DELETE</code> method</h2>
<ul>
<li data-marpit-fragment="1">Use <code>DELETE</code> to delete an existing resource, e.g. an element in a list</li>
@ -234,7 +234,7 @@
<img src="imgs/5-rest-architecture_6.png" alt="" /></li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="18" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="18" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="handling-httpdelete-requests">Handling <code>HttpDelete</code> Requests</h3>
<ul>
<li data-marpit-fragment="1">The ID is fetched from the URI<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-comment">// Controllers/ContactsController.cs</span>
@ -250,7 +250,7 @@
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="exercise invert" data-marpit-pagination="19" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="exercise invert" data-marpit-pagination="19" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="exercise-3-creating-a-delete-endpoint">Exercise 3: Creating a <code>DELETE</code> Endpoint</h3>
<p>Continue working on CourseAPI.</p>
@ -263,7 +263,7 @@ d) Return a <code>404</code> status code if a course with the corresponding ID d
<li data-marpit-fragment="2">Test with Postman.</li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="20" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="20" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h2 id="http-patch-method">HTTP <code>PATCH</code> method</h2>
<ul>
<li data-marpit-fragment="1">Use <code>PATCH</code> to <em>partially</em> update a resource
@ -275,7 +275,7 @@ d) Return a <code>404</code> status code if a course with the corresponding ID d
<li data-marpit-fragment="4">Sending and handling <code>PATCH</code> requests with ASP.NET requires some extra work and the use of a third party package <a href="http://jsonpatch.com/">JSON Patch</a></li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="21" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="21" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<ul>
<li data-marpit-fragment="1">To handle <code>PATCH</code> requests in a standardized way, install and add the following NuGet packages to your project:
<ul>
@ -291,7 +291,7 @@ d) Return a <code>404</code> status code if a course with the corresponding ID d
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="22" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="22" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<ul>
<li data-marpit-fragment="1">The body of the <code>PATCH</code> request needs to be in the following form:<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-json"><span class="hljs-punctuation">[</span><span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;op&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;replace&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;path&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;/propertyName&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;newValue&quot;</span><span class="hljs-punctuation">}</span><span class="hljs-punctuation">]</span>
</code></pre>
@ -302,7 +302,7 @@ d) Return a <code>404</code> status code if a course with the corresponding ID d
<p><img src="imgs/5-rest-architecture_7.png" alt="" style="width:1000px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="invert" data-marpit-pagination="23" style="--paginate:true;--class:invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="invert" data-marpit-pagination="23" style="--paginate:true;--class:invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="handling-httppatch-requests">Handling <code>HttpPatch</code> Requests</h3>
<ul>
<li data-marpit-fragment="1">The ID is fetched from the URI</li>
@ -323,7 +323,7 @@ d) Return a <code>404</code> status code if a course with the corresponding ID d
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9" lang="en-US" class="exercise invert" data-marpit-pagination="24" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:3wqvr8lbfisg883hr04eltgujpfjziivmd8b5evcey9;" data-marpit-pagination-total="24">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5" lang="en-US" class="exercise invert" data-marpit-pagination="24" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:lfqpvq1z79ouia9p3ld9aaj4qswwp6p9dixcybwcjc5;" data-marpit-pagination-total="24">
<h3 id="exercise-4-creating-a-patch-endpoint">Exercise 4: Creating a <code>PATCH</code> Endpoint</h3>
<p>Continue working on CourseAPI.</p>

@ -24,8 +24,8 @@ title: 4. RESTful HTTP Methods
### RESTful API
* We'll be extending our Web API into a full-blown ***RESTful API***
* More about REST in [Frontend Basics Lecture 3: REST Architecture](https://gitea.buutti.com/education/frontend-basics/src/branch/main/3-rest-architecture.md)
* A good idea to also check out [Frontend Basics Lecture 2: HTTP methods](https://gitea.buutti.com/education/frontend-basics/src/branch/main/2-http.md)
* It's a good idea to check out [Webdev Basics: HTTP methods](https://gitea.buutti.com/education/webdev-basics/src/branch/main/http.md) first
* Also, some ramblings about REST in [Webdev Basics: REST Architecture](https://gitea.buutti.com/education/webdev-basics/src/branch/main/rest-architecture.md)
* We have so far implemented `GET` and `POST` methods for reading resources from the API and creating new ones to it, respectively
* All the primary methods for following the uniform interface requirement are `GET`, `POST`, `PUT`, `PATCH` and `DELETE`
* Others exist, but these are by far most commonly used

@ -13,30 +13,36 @@
/* buutti.css */
/* @theme buutti */div#\:\$p>svg>foreignObject>section .columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns12{display:grid;grid-template-columns:1fr 2fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns21{display:grid;grid-template-columns:2fr 1fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns32{display:grid;grid-template-columns:3fr 2fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns23{display:grid;grid-template-columns:2fr 3fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .columns111{display:grid;grid-template-columns:1fr 1fr 1fr;gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .centered{display:flex;flex-direction:column;justify-content:center;text-align:center}div#\:\$p>svg>foreignObject>section .tableborderless td,div#\:\$p>svg>foreignObject>section th{border:none!important;border-collapse:collapse}div#\:\$p>svg>foreignObject>section.extra{background-color:#5d275d;background-image:linear-gradient(to bottom,#401a40,#1d0c1d);color:white}div#\:\$p>svg>foreignObject>section.extra a{color:rgb(145,255,209)}div#\:\$p>svg>foreignObject>section.exercise{background-color:#29366f;background-image:linear-gradient(to bottom,#20636a,#173742);color:white}div#\:\$p>svg>foreignObject>section.exercise a{color:rgb(211,173,255)}
/* @theme gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="1" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
/* @theme qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9 */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="1" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h1 id="databases-with-entity-framework">Databases with Entity Framework</h1>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="2" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="2" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h2 id="contents">Contents</h2>
<ul>
<li><a href="#entity-framework-ef">Entity Framework (EF)</a></li>
<li><a href="#code-first-approach">Code First approach</a></li>
<li><a href="#migrations">Migrations</a></li>
<li><a href="#migrations">Migrations</a></li>
<li><a href="#database-first-approach">Database First approach</a></li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="3" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="3" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h2 id="entity-framework-ef">Entity Framework (EF)</h2>
<ul>
<li data-marpit-fragment="1"><a href="https://learn.microsoft.com/en-us/ef/">Entity Framework</a> is an Object-Relational Mapper (ORM) made by Microsoft for the .NET framework
<li data-marpit-fragment="1">This lecture will assume you have a basic understanding of SQL databases
<ul>
<li data-marpit-fragment="2">Read <a href="https://gitea.buutti.com/education/webdev-basics/src/branch/main/sql-databases.md">Webdev basics: SQL Databases</a> first!</li>
</ul>
</li>
<li data-marpit-fragment="3"><a href="https://learn.microsoft.com/en-us/ef/">Entity Framework</a> is an Object-Relational Mapper (ORM) made by Microsoft for the .NET framework
<ul>
<li data-marpit-fragment="2">Object-Relational Mapping: converting from database representation to objects in a programming language</li>
<li data-marpit-fragment="4">Object-Relational Mapping: converting from database representation to objects in a programming language</li>
</ul>
</li>
<li data-marpit-fragment="3">Allows creation of CRUD operations without writing SQL</li>
<li data-marpit-fragment="5">Allows creation of CRUD operations without writing SQL</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="4" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="4" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="entity-framework-core-ef-core">Entity Framework Core (EF Core)</h3>
<ul>
<li data-marpit-fragment="1"><a href="https://learn.microsoft.com/en-us/ef/core/">EF Core</a> is a cross-platform version of EF</li>
@ -46,7 +52,7 @@
<li data-marpit-fragment="5">This is what we'll be using</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="5" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="5" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="code-first-vs-database-first-vs-model-first">Code First vs Database First vs Model First</h3>
<ul>
<li data-marpit-fragment="1">There are three approaches through which Entity Framework can be implemented
@ -59,7 +65,7 @@
<li data-marpit-fragment="5">Database First and Code First are the most used ones and will be introduced in this lecture</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="6" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="6" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="note-about-loading-data">Note about loading data</h3>
<ul>
<li data-marpit-fragment="1">In EF Core, you can use <a href="https://learn.microsoft.com/en-us/ef/ef6/fundamentals/relationships">navigation properties</a> in your model to load related entities</li>
@ -72,10 +78,10 @@
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="7" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="7" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h2 id="code-first-approach">Code First approach</h2>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-marpit-fragments="9" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="8" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-marpit-fragments="9" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="8" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="code-first">Code First</h3>
<ul>
<li data-marpit-fragment="1">In the Code First approach, Entity Framework will create databases and tables based on defined <em><strong>entity classes</strong></em></li>
@ -95,7 +101,7 @@
<li data-marpit-fragment="9">Not preferred for data intensive applications</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="9" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="9" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="required-packages">Required Packages</h3>
<ul>
<li data-marpit-fragment="1">Install and add the following packages to your project:
@ -110,7 +116,7 @@
<p><img src="imgs/7-databases-with-entity-framework_11.png" alt="" style="width:1000px;" /></p>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="10" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="10" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="code-first-dbcontext">Code First: <code>DbContext</code></h3>
<ul>
<li data-marpit-fragment="1">Let's begin with the Code First Approach</li>
@ -125,7 +131,7 @@ b) classes to keep the database up-to-date with CRUD operations
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="11" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="11" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="creating-a-context">Creating a context</h3>
<ul>
<li data-marpit-fragment="1">Create a context that inherits from <code>DbContext</code>
@ -145,7 +151,7 @@ b) classes to keep the database up-to-date with CRUD operations
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="12" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-marpit-fragments="2" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="12" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<ul>
<li data-marpit-fragment="1">To further configure how the database will be structured, override the <code>OnModelCreating</code> method</li>
<li data-marpit-fragment="2">In this example, one table named <code>Contact</code> with columns <code>Id</code>, <code>Name</code> and <code>Email</code> will be created:<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactsContext</span> : <span class="hljs-title">DbContext</span>
@ -162,7 +168,7 @@ b) classes to keep the database up-to-date with CRUD operations
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="13" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="13" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<ul>
<li data-marpit-fragment="1">In this example, the Contact table will be created with some starting values for <code>Id</code>, <code>Name</code> and <code>Email</code> columns:<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactsContext</span> : <span class="hljs-title">DbContext</span>
{
@ -181,7 +187,7 @@ b) classes to keep the database up-to-date with CRUD operations
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="14" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="14" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="dbcontext-as-a-service">DbContext as a Service</h3>
<ul>
<li data-marpit-fragment="1">In <code>Program.cs</code>, add the context to services with <code>AddDbContext</code> method</li>
@ -198,7 +204,7 @@ services.AddControllers().AddNewtonsoftJson();
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="15" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="15" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h2 id="migrations">Migrations</h2>
<ul>
<li data-marpit-fragment="1">As the development progresses, models and database schemas change over time
@ -214,7 +220,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="5">EFCore migrations have built-in version control; a snapshot of each version of the schema is stored</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="16" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="16" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="applying-migrations">Applying migrations</h3>
<ul>
<li data-marpit-fragment="1">Open the Package Manager Console in Visual Studio
@ -235,7 +241,7 @@ services.AddControllers().AddNewtonsoftJson();
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="17" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-marpit-fragments="3" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="17" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<ul>
<li data-marpit-fragment="1">At this point, the values you have entered (<code>Contacts</code> table in this example) should show up in the database. You can check it up e.g. in pgAdmin.</li>
</ul>
@ -256,7 +262,7 @@ services.AddControllers().AddNewtonsoftJson();
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-marpit-fragments="6" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="exercise invert" data-marpit-pagination="18" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-marpit-fragments="6" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="exercise invert" data-marpit-pagination="18" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="exercise-1-adding-context">Exercise 1: Adding Context</h3>
<p>Continue working on the CourseAPI.</p>
@ -269,7 +275,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="6">Check that the <code>Course</code> table with the starting values has appeared to the database</li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="19" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-marpit-fragments="6" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="19" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="using-dbcontext-in-the-api">Using DbContext in the API</h3>
<ul>
<li data-marpit-fragment="1">Because <code>DbContext</code> is added to services, it can be accessed from any other service, such as the repository</li>
@ -283,7 +289,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="6">After modifying the <code>DbSet</code>, update the changes to the database with the <code>DbContext.SaveChanges()</code> method</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="20" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="20" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="injecting-dbcontext">Injecting DbContext</h3>
<ul>
<li data-marpit-fragment="1">Inject the <code>DbContext</code> to your repositories as you would any other service:<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactRepository</span> : <span class="hljs-title">IContactRepository</span>
@ -300,7 +306,7 @@ services.AddControllers().AddNewtonsoftJson();
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="21" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="21" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="dbcontext-read-operations">DbContext: Read Operations</h3>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactRepository</span> : <span class="hljs-title">IContactRepository</span>
{
@ -315,7 +321,7 @@ services.AddControllers().AddNewtonsoftJson();
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="22" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="22" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="dbcontext-create-operations">DbContext: Create Operations</h3>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactRepository</span> : <span class="hljs-title">IContactRepository</span>
{
@ -333,7 +339,7 @@ services.AddControllers().AddNewtonsoftJson();
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="23" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="23" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="dbcontext-update-operations">DbContext: Update Operations</h3>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactRepository</span> : <span class="hljs-title">IContactRepository</span>
{
@ -354,7 +360,7 @@ services.AddControllers().AddNewtonsoftJson();
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="24" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="24" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="dbcontext-delete-operations">DbContext: Delete Operations</h3>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ContactRepository</span> : <span class="hljs-title">IContactRepository</span>
{
@ -372,7 +378,7 @@ services.AddControllers().AddNewtonsoftJson();
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="25" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="exercise invert" data-marpit-pagination="25" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="25" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="exercise invert" data-marpit-pagination="25" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="exercise-2-crud-on-the-db">Exercise 2: CRUD on the DB</h3>
<p>Continue working on CourseAPI.</p>
@ -381,7 +387,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="2">Test with Postman. Keep refreshing the DB in pgAdmin or creating queries with psql to make sure the requests work as intended</li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="26" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="26" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="26" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="26" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="summing-things-up">Summing Things Up</h3>
<ul>
<li data-marpit-fragment="1">Now the API has been hooked up to a PostgreSQL database</li>
@ -390,7 +396,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="4">Controllers accepting HTTP requests have access to the repository</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="27" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="27" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="27" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="27" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="efcore-code-first-checklist">EFCore Code First Checklist</h3>
<ol>
<li data-marpit-fragment="1">Install required packages</li>
@ -400,7 +406,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="5">Add CRUD operations to the database repository</li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="28" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="28" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="28" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="28" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="modifying-the-relations">Modifying the Relations</h3>
<ul>
<li data-marpit-fragment="1">Let's change the structure of our Contacts API by adding a new class <code>Account</code>
@ -412,7 +418,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="4">Emails will be removed from the <code>Contacts</code> table</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="29" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="29" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="29" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="29" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-csharp"><span class="hljs-comment">// Models/Contact.cs</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Contact</span>
{
@ -432,13 +438,13 @@ services.AddControllers().AddNewtonsoftJson();
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="30" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="30" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="30" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="30" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<ul>
<li data-marpit-fragment="1">Adding a migration at this point will result in a warning:<br />
<img src="imgs/7-databases-with-entity-framework_14.png" alt="" style="width:1000px;" /></li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="31" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="31" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="31" data-marpit-fragments="5" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="31" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<div class='columns32' markdown='1'>
<div markdown='1'>
<ul>
@ -460,7 +466,7 @@ services.AddControllers().AddNewtonsoftJson();
</div>
</div>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="32" data-marpit-fragments="4" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="exercise invert" data-marpit-pagination="32" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="32" data-marpit-fragments="4" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="exercise invert" data-marpit-pagination="32" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="exercise-3-adding-migrations">Exercise 3: Adding Migrations</h3>
<p>Continue working on CourseAPI.</p>
@ -471,10 +477,10 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="4">Update the database. Check that the changes show up in the database with pgAdmin</li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="33" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="33" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="33" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="33" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h2 id="database-first-approach">Database First approach</h2>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="34" data-marpit-fragments="7" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="34" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="34" data-marpit-fragments="7" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="34" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="what-is-the-database-first-approach">What is the Database First approach?</h3>
<ul>
<li data-marpit-fragment="1">This is the other approach for creating a connection between the database and the application</li>
@ -489,7 +495,7 @@ services.AddControllers().AddNewtonsoftJson();
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="35" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="35" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="35" data-marpit-fragments="4" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="35" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="scaffolding">Scaffolding</h3>
<ul>
<li data-marpit-fragment="1">Use the Package Manager Console to &quot;reverse engineer&quot; the code for an existing database
@ -503,7 +509,7 @@ services.AddControllers().AddNewtonsoftJson();
<li data-marpit-fragment="4">Using the connection string corresponding to your database, this will create all the classes for the entities in the DB as well as the context class</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="36" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="exercise invert" data-marpit-pagination="36" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="36" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="exercise invert" data-marpit-pagination="36" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="exercise-4-database-first">Exercise 4: Database First</h3>
<p>Create a new ASP.NET Core web app using the API template.</p>
@ -514,13 +520,13 @@ b) by copying the <code>&lt;PackageReference&gt;</code> lines from the <code>.cs
<li data-marpit-fragment="2">Scaffold the <code>sqlpractice</code> database created in <a href="sql-databases#exercise-1-preparing-the-database">SQL Databases Exercise 1</a> to the project by using the Database First approach. If you have not yet created the database in PostgreSQL, it can be found <a href="code-examples/example-query.sql">here</a></li>
</ol>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="37" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="invert" data-marpit-pagination="37" style="--paginate:true;--class:invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="37" data-marpit-fragments="1" data-paginate="true" data-class="invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="invert" data-marpit-pagination="37" style="--paginate:true;--class:invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="reading-authentication-with-roles">Reading: Authentication with roles</h3>
<ul>
<li data-marpit-fragment="1"><a href="https://www.c-sharpcorner.com/article/jwt-token-creation-authentication-and-authorization-in-asp-net-core-6-0-with-po/">Here's</a> an example how to do a role-based authentication by using JWT tokens</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="38" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh" lang="en-US" class="exercise invert" data-marpit-pagination="38" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:gqy7k3kdx5d6t13nmmhm7jdgeg2yxye7r5enweiq2sgh;" data-marpit-pagination-total="38">
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="38" data-marpit-fragments="2" data-paginate="true" data-class="exercise invert" data-heading-divider="5" data-theme="qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9" lang="en-US" class="exercise invert" data-marpit-pagination="38" style="--paginate:true;--class:exercise invert;--heading-divider:5;--theme:qxwzalhzytjx5wnlf6losqvbl44tf0bt7if1oe7ch9;" data-marpit-pagination-total="38">
<h3 id="exercise-5-extra-connection">Exercise 5 (Extra): Connection</h3>
<p>Continuing the previous exercise,</p>

@ -16,11 +16,14 @@ title: 5. Databases with Entity Framework
- [Entity Framework (EF)](#entity-framework-ef)
- [Code First approach](#code-first-approach)
- [Migrations](#migrations)
- [Migrations](#migrations)
- [Database First approach](#database-first-approach)
## Entity Framework (EF)
* This lecture will assume you have a basic understanding of SQL databases
* Read [Webdev basics: SQL Databases](https://gitea.buutti.com/education/webdev-basics/src/branch/main/sql-databases.md) first!
* [Entity Framework](https://learn.microsoft.com/en-us/ef/) is an Object-Relational Mapper (ORM) made by Microsoft for the .NET framework
* Object-Relational Mapping: converting from database representation to objects in a programming language
* Allows creation of CRUD operations without writing SQL

@ -7,7 +7,6 @@
| 3 | [MVP Pattern and Repositories](3-mvc-pattern-and-repositories.md) | [Download slides](3-mvc-pattern-and-repositories-slides.html?raw=1) |
| 4 | [RESTful HTTP Methods](4-restful-http-methods.md) | [Download slides](4-restful-http-methods-slides.html?raw=1) |
| 5 | [Model Validation & API Design](5-model-validation-and-designing-apis.md) | [Download slides](5-model-validation-and-designing-apis-slides.html?raw=1) |
| | [SQL Databases](sql-databases.md) | [Download slides](5-model-validation-and-designing-apis-slides.html?raw=1) |
| 6 | [Databases with Entity Framework](6-databases-with-entity-framework.md) | [Download slides](6-databases-with-entity-framework-slides.html?raw=1) |
| 7 | [Authentication and Authorization](7-authentication-and-authorization.md) | [Download slides](7-authentication-and-authorization-slides.html?raw=1) |
| 8 | [Testing](8-testing.md) | [Download slides](8-testing-slides.html?raw=1) |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because one or more lines are too long

@ -1,400 +0,0 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: SQL Databases
---
# SQL Databases
<!-- headingDivider: 5 -->
<!-- class: invert -->
## What is SQL?
* SQL, Structured Query Language is a language used to organize and manipulate data in a database
* Originally developed by IBM in the 70's
* Quickly became the most popular database language
```sql
SELECT id, email
FROM users
WHERE first_name = 'Teppo';
```
## Relational Database Management Systems
* In relational databases, values are stored in *__tables__*
* Each table has *__rows__* and *__columns__*
* Data is displayed in a two-dimensional matrix
* Values in a table are related to each other
* Values can also be related to values in other tables
* A relational database management system (RDBMS) is a program that executes queries to relational databases
---
![](imgs/7-databases-with-entity-framework_0.png)
[https://db-engines.com/en/ranking](https://db-engines.com/en/ranking)
## PostgreSQL
* Free and open-source, cross-platform relational database management system
* Emphasizes extensibility and SQL compliance
* Fully ACID-compliant (atomicity, consistency, isolation and durability)
* Used in conjunction with ***pgAdmin***
* Administration and development platform for PostgreSQL
* Cross-platform, features a web interface
* Basically a control panel application for your PostgreSQL database
### PostgreSQL: Creating a Database
<div class='columns' markdown='1'>
<div markdown='1'>
With pgAdmin:
1) Right-click *Servers > my-postgres > Databases*
2) Select _Create > Database..._
3) Insert a name for the database and hit _Save_
</div>
<div markdown='1'>
With psql:
1) Enter command
```sql
CREATE DATABASE <database-name>;
```
</div>
</div>
<div class='centered'>
![](imgs/7-databases-with-entity-framework_1.png)
</div>
### PostgreSQL: Querying
With pgAdmin:
1) Right-click _sqlpractice > Query tool..._
2) Insert a query into the _Query Editor_ and hit _Execute_ (F5)
<div class='columns23' markdown='1'>
<div markdown='1'>
![w:345](imgs/7-databases-with-entity-framework_2.png)
</div>
<div markdown='1'>
![](imgs/7-databases-with-entity-framework_3.png)
</div>
</div>
---
With psql:
1) List all available databases with `\l`
2) Connect to the created database with `\c <database-name>`
3) List all tables in the database with `\dt`
4) Type a query and press enter
* Here's an [example query](code-examples/example-query.sql)
## Editing Data with pgAdmin
<div class='columns' markdown='1'>
<div markdown='1'>
* Inspect and edit data in pgAdmin by right-clicking a table and selecting _View/Edit Data_
</div>
<div markdown='1'>
![](imgs/7-databases-with-entity-framework_4.png)
</div>
</div>
---
<div class='columns' markdown='1'>
<div markdown='1'>
* Individual values in the table can be directly modified by double clicking the value and then editing the value in the visual user interface
* Save the changes by pressing the _Save Data Changes_ button
</div>
<div markdown='1' class='centered'>
![](imgs/7-databases-with-entity-framework_5.png)
![](imgs/7-databases-with-entity-framework_6.png)
</div>
</div>
## Exercise 1: Preparing the database
<!--_class: "exercise invert" -->
Using either PgAdmin or PSQL,
1) Create a new database called `sqlpractice`
2) Insert the provided [example query](code-examples/example-query.sql) to the new database
3) Verify that the query has created new tables to your database
## Basic SQL queries
* `SELECT`
* `INSERT`
* `DELETE`
* `UPDATE`
* `CREATE` & `DROP`
### Querying data with `SELECT`
* Syntax:
```sql
SELECT column1, column2, column3 FROM table_name;
```
* Examples:
```sql
SELECT full_name, email FROM users;
SELECT full_name AS name, email FROM users;
SELECT * FROM users;
```
### Filtering data with `WHERE`
* Syntax:
```sql
SELECT column1, column2 FROM table_name WHERE condition;
```
<div class='columns12' markdown='1'>
<div markdown='1'>
* Text is captured in **_single quotes_**.
* `LIKE` condition uses the `%` sign as a wildcard.
* `IS` and `IS NOT` are also valid operators.
</div>
<div markdown='1'>
* Example:
```sql
SELECT full_name FROM users
WHERE full_name = 'Teppo Testaaja';
SELECT * FROM books WHERE name LIKE '%rr%';
SELECT * FROM books WHERE author IS NOT null;
```
</div>
</div>
### Ordering data with `ORDER BY`
* Syntax:
```sql
SELECT column1 FROM table_name ORDER BY column1 ASC;
```
* Examples:
```sql
SELECT full_name FROM users
ORDER BY full_name ASC;
SELECT full_name FROM users
ORDER BY full_name DESC;
```
### Combining data with `JOIN`
* Also known as `INNER JOIN`
* Corresponds to ***intersection*** from [set theory](https://en.wikipedia.org/wiki/Set_theory)
<div class='centered'>
![w:500px](imgs/7-databases-with-entity-framework_7.png)
</div>
#### JOIN examples
```sql
SELECT
users.id, users.full_name, borrows.id,
borrows.user_id, borrows.due_date, borrows.returned_at
FROM users
JOIN borrows ON
users.id = borrows.user_id;
```
```sql
SELECT
U.full_name AS name,
B.due_date AS due_date,
B.returned_at AS returned_at
FROM users AS U
JOIN borrows AS B ON
U.id = B.user_id;
```
### Combining with `LEFT JOIN`
<div class='columns' markdown='1'>
<div markdown='1'>
* Also known as `LEFT OUTER JOIN`
* Example:
```sql
SELECT
U.full_name AS name,
B.due_date AS due_date,
B.returned_at AS returned_at
FROM users AS U
LEFT JOIN borrows AS B ON
U.id = B.user_id;
```
</div>
<div markdown='1'>
![](imgs/7-databases-with-entity-framework_8.png)
</div>
</div>
### Exercise 2: Querying the library
<!--_class: "exercise invert" -->
Using SQL queries, get
1) all columns of `borrows` that are borrowed before `2020-10-27`
2) all columns of `borrows` that are returned
3) columns `user.full_name` and `borrows.borrowed_at` of the user with an `id` of 1
4) columns `book.name`, `book.release_year` and `language.name` of all books that are released after 1960
### Inserting data with `INSERT`
* Syntax
```sql
INSERT INTO table_name (column1, column2, column3) VALUES (value1, value2, value3);
```
* Example
```sql
INSERT INTO users (full_name, email, created_at)
VALUES ('Pekka Poistuja', 'pekka.poistuja@buutti.com', NOW());
```
* Since id is not provided, it will be automatically generated.
### Updating data with `UPDATE`
* Syntax
```sql
UPDATE table_name SET column1 = value1, column2 = value2 WHERE condition;
```
* *__Notice:__* if a condition is not provided, all rows will be updated!
* If updating only one row, it is usually best to use `id`.
* Example
```sql
UPDATE users SET email = 'taija.testaaja@gmail.com' WHERE id = 2;
```
## Removing data with `REMOVE`
* Syntax
```sql
DELETE FROM table_name WHERE condition;
```
* Again, if the _condition_ is not provided, `DELETE` affects _all_ rows
* Before deleting, it is a good practice to execute an equivalent `SELECT` query to make sure that only the proper rows will be affected.
* Example:
```sql
SELECT * FROM users WHERE id = 5;
DELETE FROM users WHERE id = 5;
```
### Exercise 3: Editing data
<!--_class: "exercise invert" -->
1) Postpone the due date of the borrow with an `id` of `1` by two days in the `borrows` table
2) Add a couple of new books to the `books` table
3) Delete one of the borrows.
### Initializing data with `CREATE TABLE`
* Before data can be manipulated, a database and its tables need to be initialized.
<div class='columns' markdown='1'>
<div markdown='1'>
* Syntax
```sql
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
```
</div>
<div markdown='1'>
* Example:
```sql
CREATE TABLE "users" (
"id" SERIAL PRIMARY KEY,
"full_name" varchar NOT NULL,
"email" varchar UNIQUE NOT NULL,
"created_at" timestamp NOT NULL
);
```
</div>
</div>
### Removing data with `DROP`
* In order to remove tables or databases, we use a `DROP` statement
```sql
DROP TABLE table_name;
DROP DATABASE database_name;
```
* These statements do not ask for confirmation and there is no undo feature. Take care when using a drop statement.
---
* I'm legally obliged to include this XKCD comic here.
![](https://imgs.xkcd.com/comics/exploits_of_a_mom_2x.png)
## NoSQL
* In addition to SQL databases, there's ***NoSQL***
* There are many differing definitions, but...
* most agree that NoSQL databases store data in a format other than tables
* They can still store relational data - just _differently_
* Four different database types:
* Document databases
* Key-value databases
* Wide-column stores
* Graph databases
* Example database engines include [MongoDB](https://www.mongodb.com/), [Redis](https://redis.io/) and [Cassandra](https://cassandra.apache.org/_/index.html)
* For more info, see [MongoDB: What is NoSQL?](https://www.mongodb.com/resources/basics/databases/nosql-explained)
## Object-Relational Mappers
* Object-Relational Mappers, or ORMs allow the developer to write code instead of SQL to perform CRUD operations on their database
* An abstraction layer between code and database
* Can make database logic easier to read and write
* Prevents SQL injection by sanitizing input (see the comic before...)
* ...but sometimes you'd rather just write the SQL queries themselves
* Some popular ORMs:
* Hibernate (Java)
* EFCore (.NET)
* Sequelize (Node.js)
* TypeORM (TypeScript)
Loading…
Cancel
Save