<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: jpeg729</title>
    <description>The latest articles on DEV Community by jpeg729 (@jpeg729).</description>
    <link>https://dev.to/jpeg729</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F166459%2F0a6b4717-3f2f-48a5-a04d-3d64c4175d82.png</url>
      <title>DEV Community: jpeg729</title>
      <link>https://dev.to/jpeg729</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jpeg729"/>
    <language>en</language>
    <item>
      <title>How to mock the db in EFCore</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Sun, 19 Nov 2023 08:37:39 +0000</pubDate>
      <link>https://dev.to/jpeg729/how-to-mock-the-db-in-efcore-fbe</link>
      <guid>https://dev.to/jpeg729/how-to-mock-the-db-in-efcore-fbe</guid>
      <description>&lt;p&gt;There are several options. In this article we will list the options we know of and any crazy ideas we might have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desirata
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We want the application code to use EntityFramework as if nothing had changed.&lt;/li&gt;
&lt;li&gt;The "database" must be seeded with some initial data, and if possible, any views and stored procedures.&lt;/li&gt;
&lt;li&gt;The "database" should behave "similarly" to the production database.&lt;/li&gt;
&lt;li&gt;We must be able to query this database in the tests in order to verify the results.&lt;/li&gt;
&lt;li&gt;It may be nice to have EntityFramework tell us what it has saved to the database, instead of having to query the db.&lt;/li&gt;
&lt;li&gt;The tests using this database must setup and teardown fast, otherwise they won't run fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  EntityFramework's InMemory provider (not recommended)
&lt;/h3&gt;

&lt;p&gt;Even Microsoft's documentation say this is not recommended.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite
&lt;/h3&gt;

&lt;p&gt;EntityFramework has great support for SQLite and any required modifications to EntityFramework's model can be applied in the test project.&lt;/p&gt;

&lt;p&gt;If you have an existing .db file, you can copy it for each test, or maybe even open the original file in one connection, then for each test, open a new db in memory and copy the db from the file connection into the new memory db. That might be a touch faster.&lt;/p&gt;

&lt;p&gt;Disadvantage: This isn't the database technology used in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  TestContainers
&lt;/h3&gt;

&lt;p&gt;TestContainers can be used to create a docker container per-test, so you can use a real SQL database.&lt;/p&gt;

&lt;p&gt;Disadvantage: This is probably slower.&lt;/p&gt;

&lt;h3&gt;
  
  
  LocalDb
&lt;/h3&gt;

&lt;p&gt;If the production db is SQL Server, then we could use LocalDb for testing. LocalDb is a version of SQL Server that runs in the user's session. It comes with Visual Studio, but can be installed independently. &lt;/p&gt;

&lt;p&gt;LocalDb can be used to open a .mdf file directly, and we can make a copy for each test.&lt;/p&gt;

&lt;p&gt;This should be faster than TestContainers, and may compare favourably to sqlite.&lt;/p&gt;

&lt;p&gt;Disadvantage: It requires LocalDb to be installed. So maybe we need to use TestContainers at least for test run on CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article is about collecting ideas, and may be updated later.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Exploring testing AspNet web applications</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Tue, 17 Oct 2023 08:38:28 +0000</pubDate>
      <link>https://dev.to/jpeg729/exploring-testing-aspnet-web-applications-1ncp</link>
      <guid>https://dev.to/jpeg729/exploring-testing-aspnet-web-applications-1ncp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Testing lies at the heart of ensuring the functionality, reliability, and security of any software application, and ASP.NET web applications are no exception. In this series of articles, we delve into the intricate world of testing ASP.NET web applications using C#. From unit tests that scrutinize individual components to end-to-end tests ensuring the seamless operation of the entire application, we explore various testing approaches and methodologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Goal
&lt;/h2&gt;

&lt;p&gt;Imagine you have an ASP.NET web application, and you're faced with the challenge of testing it comprehensively. How do you ensure its logic is flawless, its data remains coherent, and its user interactions are seamless? This series aims to answer these questions and more, providing insights into different aspects of testing, including:&lt;/p&gt;

&lt;p&gt;Automated Tests at Different Scales: We'll discuss unit tests, integration tests, and end-to-end tests. Each type has its unique purpose, allowing us to validate different layers of our application's functionality.&lt;/p&gt;

&lt;p&gt;Testing Code with External Dependencies: Real-world applications often rely on external services and databases. We'll explore strategies to test code that interacts with these dependencies, ensuring our tests remain robust and independent.&lt;/p&gt;

&lt;p&gt;Manual Testing: While automated tests are invaluable, some scenarios require the human touch. We'll explore when and how manual testing fits into the overall testing strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the Context: The Application
&lt;/h2&gt;

&lt;p&gt;In the articles to follow, our focus will be on testing the application logic and database access of an ASP.NET web application. This application comprises:&lt;/p&gt;

&lt;p&gt;An interactive website provides the user interface through which users interact with the application. The website communicates with a backend via a mostly json API. I'd like to say REST, but let's be real, most of the time it's more like RPC.&lt;/p&gt;

&lt;p&gt;A backend in Modern C# with ASP.NET: The application logic is predominantly written in C#, employing services organized using ASP.NET dependency injection. However some logic resides in SQL Views and Stored Procedures. A bad choice? Maybe, but we don't always get to choose.&lt;/p&gt;

&lt;p&gt;Database Storage: Data is stored in SQL Server using EntityFramework 7. While EntityFramework simplifies database access, it presents challenges in terms of testing, especially when it comes to mocking.&lt;/p&gt;

&lt;p&gt;Application Settings: Any sufficiently complex application probably has a few settings stored in the database. Even a TODO application might have different types of tasks with different workflows defined in the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Considerations
&lt;/h2&gt;

&lt;p&gt;Testing is not one-size-fits-all; it involves making various decisions and trade-offs based on project requirements and goals. A project may have several test suites with different trade-offs. In this series, we explore different testing styles and goals, considering factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Speed:&lt;/em&gt; It is important, especially in Test-Driven Development (TDD) scenarios, to have tests that run fast, giving feedback quickly. Such tests, must probably be written to focus on individual components, validating their behavior without relying on external dependencies. The trade-off is how far you are willing to go to mock external dependencies. These tests are often called "Unit tests" because they test parts in isolation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;System coverage:&lt;/em&gt; Testing parts in isolation while mocking their dependencies only gets you so far. To ensure comprehensive coverage, we delve into integration tests that assess how these components interact when combined. Integration tests provide a more holistic view of the application, examining the integration points where potential issues might arise. True system coverage may require communicating with services outside of the application, such as a real database. The trade-off lie in how far you go to provide outside services equivalent to the production environment, or how far you go to replace them with mocks and/or fakes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Reliability and Stability:&lt;/em&gt; Beyond the functionalities, a robust application must be reliable and stable under various conditions. Load testing, stress testing, and performance testing become crucial. These tests assess how the application behaves under different loads and stress levels, ensuring it can handle real-world usage scenarios without compromising on speed and responsiveness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Monitoring:&lt;/em&gt; No matter how completely we have tested the application logic and reliability, things will get messed up eventually. Monitoring probably ought to be sufficient to debug and fix the problems easily. The trade-offs to be explored include how much detail you want to collect and store.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Maintainability:&lt;/em&gt; As the project evolves, tests need to evolve too. Writing maintainable tests involves considering their longevity and ease of modification. Test suites should be adaptable, allowing developers to refactor code confidently without the fear of breaking existing functionalities. Balancing thorough testing with the ability to make changes to the codebase is essential for long-term project health.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series, we'll explore these key considerations in depth, offering insights into crafting test suites that strike the right balance between speed, coverage, reliability, and maintainability. By understanding these fundamental principles, you'll be better equipped to make informed decisions tailored to your project's unique requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Testing ASP.NET web applications involves a delicate balance of various testing approaches, each serving a specific purpose. In the articles that follow, we will explore various approaches. Some may be good, some may be crazy. This is exploration, not a thesis. The goal is not to explain the one true way, but to learn.&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>csharp</category>
      <category>testing</category>
    </item>
    <item>
      <title>AutoMapper: converting entities to views at runtime</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Thu, 05 Sep 2019 15:05:53 +0000</pubDate>
      <link>https://dev.to/jpeg729/automapper-converting-entities-to-views-at-runtime-4i5c</link>
      <guid>https://dev.to/jpeg729/automapper-converting-entities-to-views-at-runtime-4i5c</guid>
      <description>&lt;p&gt;I have put off writing this post for quite some time since I didn't have a viable alternative and others have written about the problems they have experienced with AutoMapper. For instance &lt;a href="https://cezarypiatek.github.io/post/why-i-dont-use-automapper/" rel="noopener noreferrer"&gt;Why I don't use AutoMapper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now I do have an alternative, so here goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AutoMapper does
&lt;/h2&gt;

&lt;p&gt;When you use an ORM (object relational mapper) to load data from your database, you often end up loading data into objects (which I will call entities) containing way more data than you actually need at that moment. Automapper lets you transform those objects into smaller data transfer objects (DTOs) more adapted for your need at that moment.&lt;/p&gt;

&lt;p&gt;For example, you could have Book and Author classes like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookEntity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ISBN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;AuthorEntity&lt;/span&gt; &lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorEntity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;PreferedGenre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// I put "List" for ease of understanding, but &lt;/span&gt;
    &lt;span class="c1"&gt;// EntityFramework 6 actually requires an "ICollection".&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you might want to send only the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorWithBooksDto&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;BooksCount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I put the BookDto class inside the AuthorWithBooksDto in order to avoid reusing it elsewhere in the codebase.&lt;/p&gt;

&lt;p&gt;So you define a map using AutoMapper&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorProfile&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Profile&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AuthorProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CreateMap&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you use it like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorDto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;authorEntity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even better you can use AutoMapper's queryable extensions to only load the required properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorDtos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProjectTo&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mapping will be translated into SQL in order to optimise the data transfer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upsides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It is super easy to use.&lt;/li&gt;
&lt;li&gt;It works nicely with EntityFramework and other ORMs.&lt;/li&gt;
&lt;li&gt;It works pretty well.&lt;/li&gt;
&lt;li&gt;It is super easy to use (Did I already say that?)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Downsides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If your mappings aren't defined quite right you can get cryptic runtime errors, such as OutOfMemory, or NullReferenceException's that can't tell you exactly what was null.&lt;/li&gt;
&lt;li&gt;Since you define the mappings without referring to all the properties that get mapped, your editor cannot tell you exactly which properties are used and where.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;AutoMapper does a great job, but it does it at runtime and I think we can do better.&lt;/p&gt;

&lt;p&gt;I don't want to have to write all my mappings by hand, but I do want my code editor to be able to tell me exactly where each property is used, and I do want an easy equivalent to AutoMapper's query projection extensions.&lt;/p&gt;

&lt;p&gt;This means I need a tool that can generate code for the mappings when I am writing the code. It also has to be able to generate mappings as C# Expressions because that is what EntityFramework uses to generate its SQL queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MappingGenerator extension
&lt;/h2&gt;

&lt;p&gt;If you use Visual Studio 2017+ you can use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=54748ff9-45fc-43c2-8ec5-cf7912bc3b84.mappinggenerator" rel="noopener noreferrer"&gt;MappingGenerator&lt;/a&gt; which as its name suggests, generates mappings.&lt;/p&gt;

&lt;p&gt;Here is how it works...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Type out the map function's signature&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public AuthorWithBooksDto MapFrom(AuthorEntity author)
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Press Ctrl+. at the end of the line and choose the proposed code fix&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjpeg729%2Fblog%2Fmaster%2FMappingGenerator%2520MapFrom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjpeg729%2Fblog%2Fmaster%2FMappingGenerator%2520MapFrom.png" alt="map generation at work"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the generated code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt; &lt;span class="nf"&gt;MapFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorEntity&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorBook&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authorBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;BooksCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, you are going to tell me that isn't an Expression mapping and it can't be used with EntityFramework, and you would be right, but watch this...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Type out the signature, it is a little more complicated, I will grant you that&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MapAuthorWithBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put the text cursor in between the curly braces, press Ctrl+., and choose "Initialize with lambda parameter".&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjpeg729%2Fblog%2Fmaster%2FMappingGenerator%2520Expression.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjpeg729%2Fblog%2Fmaster%2FMappingGenerator%2520Expression.png" alt="expression map generation at work"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the generated code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MapAuthorWithBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entityBook&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AuthorWithBooksDto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;BooksCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test its use&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MapAuthorWithBooks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// only the required columns are included&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorsWithBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What do we gain?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Visual Studio no longer tells us that the properties of our entities have zero references.&lt;/li&gt;
&lt;li&gt;No more memory overflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What problems remain?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If a null reference exception happens during the mapping Visual Studio 2017 can't tell you which precise line caused it, so you then have to do things like commenting out most of the mapping until you find the culprit. I imagine nullable reference types will help resolve this problem.&lt;/li&gt;
&lt;li&gt;If you want Expression maps &lt;em&gt;and&lt;/em&gt; compiled maps you either have to generate code for both, or you have to compile the expression at runtime, in which case you loose the ability to set breakpoints inside the mapping code.&lt;/li&gt;
&lt;li&gt;Organising your maps becomes a bigger problem than it was. Adding a static method MapFrom to each Dto class might be a great idea.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AutoMapper is great, and while I can reproduce much of what I can do with AutoMapper using generated mapping code, I am not certain that it is a huge advantage.&lt;/p&gt;

&lt;p&gt;The main use case for mappings seems to be generating models to send over the wire, and there are many alternative approaches. gRPC and GraphQL are alternatives that may have their own advantages.&lt;/p&gt;

&lt;p&gt;Even if you prefer using AutoMapper, do try out the MappingGenerator extension because it has many useful capabilities.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using NoSQL as a cache for views</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Tue, 02 Jul 2019 21:24:55 +0000</pubDate>
      <link>https://dev.to/jpeg729/using-elasticsearch-as-a-cache-for-views-4kbi</link>
      <guid>https://dev.to/jpeg729/using-elasticsearch-as-a-cache-for-views-4kbi</guid>
      <description>&lt;p&gt;Last time we spoke about the pros and cons of using EntityFramework to manage our database access. This time we will cover our use of a NoSQL database primarily as a cache. We also use it for fancy full text queries, but we won't cover that in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  NoSQL as a cache
&lt;/h2&gt;

&lt;p&gt;In the database we have an Authors table, a Books table, a Publishers table, a Marketers table, a Meetings table, and various other tables containing useful info related to these.&lt;/p&gt;

&lt;p&gt;The relationships are vaguely as follows: Each Author has many Books, each Book has a Publisher and a Marketer, (and therefore each Author is linked by extension to several Publishers and Marketers). There are also Meetings of various types which can involve some or all of these actors.&lt;/p&gt;

&lt;p&gt;(Disclaimer: these table names are fictitious, however the relationships between them do resemble the sorts of relations that I have to deal with at work.)&lt;/p&gt;

&lt;p&gt;Now, we need to be able to display the books in a list with their Titles, Authors, Publishers and various assorted details. We also want the user to be able to specify search terms that could match the book's title, the author's name, the publisher's name, the themes that are found in the book, and so on. Now EntityFramework 6 can do all the fancy joins needed to deliver all of this detail, but the requests are far from optimised, and what's more, we need to deliver all of this information page by page. Besides SQL Server isn't great at full text querying. So we put everything into our NoSQL database and access it from there.&lt;/p&gt;

&lt;p&gt;A NoSQL database stores json documents and indexes them for querying. We fill the indices by loading the entities from SQL Server using a bunch of &lt;code&gt;Include&lt;/code&gt;s and then we push them into the relevant index in our NoSQL database. The code looks something like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publisher&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batchsize&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;noSqlClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Naturally, there are other list views that we need to populate. For example, a list of Authors with various accompanying details, and a list of Publishers with different details. Hence we end up with three different indices each containing a subset of the data seen from a different angle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad design
&lt;/h2&gt;

&lt;p&gt;Many of you will tell me that we are doing it wrong, and I will agree with you. It is inefficient and not particularly useful to store entire entities with all their fields, plus their related entities with all &lt;em&gt;their&lt;/em&gt; fields when we only need subsets of all that information for our views. Instead we should store view models containing a more limited amount of data sufficient for the views we need to present to the user, plus the fields needed for the various search options. But the app wasn't designed like that and we can't take too much time out from implementing new features, so we change it too quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difficulties
&lt;/h2&gt;

&lt;p&gt;Obviously, such an architecture comes with a number of drawbacks, for instance...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keeping the cache up to date&lt;/li&gt;
&lt;li&gt;EntityFramework is pretty slow at loading an entity with lots of many-to-many joins&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Keeping it up to date
&lt;/h3&gt;

&lt;p&gt;This is a kicker because whenever a publisher's details are modified, for example, we need to update all the authors in the authors' index who have books published by that publisher. Likewise when we update an author's details we need to update his/her document in the authors' index, and the publishers he/she has used in the publishers' index. And so on...&lt;/p&gt;

&lt;p&gt;So how do we manage that infallibly and efficiently?&lt;/p&gt;

&lt;p&gt;Well, we manually transformed the list of &lt;code&gt;Include&lt;/code&gt;s into a set of recipes for detecting which indexed entities would be affected by an update to any child entity. Then we added some custom code that would automatically run each time we call &lt;code&gt;ctx.SaveChanges()&lt;/code&gt;. This custom code uses the recipes to detect which documents of each index need updating, then loads the root entities from our NoSQL database, loads the child entities from the database with any necessary sub-&lt;code&gt;Include&lt;/code&gt;s, and patches the root entities and stores the result back into our NoSQL database. This somewhat more efficient than loading the root entities with their &lt;code&gt;Include&lt;/code&gt;s and re-indexing the whole lot.&lt;/p&gt;

&lt;h3&gt;
  
  
  EntityFramework join optimisation
&lt;/h3&gt;

&lt;p&gt;We noticed recently that when loading the authors in order to fill the authors' index, EF would pause for nearly a full minute before it started transferring any data. We tested the query itself and it wasn't anywhere near that expensive.&lt;/p&gt;

&lt;p&gt;EntityFramework.Plus provides an &lt;code&gt;.IncludeOptimized&lt;/code&gt; extension method that is faster than EntityFramework's &lt;code&gt;.Include&lt;/code&gt; method. But with two drawbacks. It doesn't support many-to-many joins, and it doesn't support &lt;code&gt;.AsNoTracking()&lt;/code&gt;. Now obviously, if we are loading entities solely in order to load them into our NoSQL database, we don't need EntityFramework to track the changes to those entities, so we should be able to optimise a little by asking EF not to track changes.&lt;/p&gt;

&lt;p&gt;We ended up optimising this by loading the Authors with &lt;code&gt;AsNoTracking&lt;/code&gt;, then loading the Books in a separate query also with &lt;code&gt;AsNoTracking&lt;/code&gt; and manually attaching each book to the right author. The total time went down from 1 minute 45 seconds, to around 25 seconds. Running the queries in parallel allowed us to nearly halve that again.&lt;/p&gt;

&lt;p&gt;Loading an Author from SQL Server using this method takes around 30-40ms, whereas loading the same Author with all the related entities from our NoSQL database takes only ~1ms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code maintenance
&lt;/h3&gt;

&lt;p&gt;Unfortunately, instead of a single list of &lt;code&gt;Include&lt;/code&gt;s we now have some other bits of code to maintain as well.&lt;/p&gt;

&lt;p&gt;The recipes for keeping the indices up-to-date could be fairly easily generated from the list of &lt;code&gt;Include&lt;/code&gt;s using reflection, but we haven't taken the time to do it yet.&lt;/p&gt;

&lt;p&gt;The code for the schema generation is fully automatic and needs no maintenance. It just needs an up-to-date list of &lt;code&gt;Include&lt;/code&gt;s and does its magic automatically. Personally, I am very happy about this because the code that does this is a pretty ugly mess of reflection and Expression tree building.&lt;/p&gt;

&lt;p&gt;The code for optimised loading needs adjusting manually each time. In theory this code could also be generated automatically at runtime, but this would be pretty hard to do. The tricky thing is figuring out which navigation properties to use to attach child entities to, though I suspect we could extract those details from EF 6 if we really tried, (or if we read parts of the source code for EntityFramework.Plus).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;Storing view models instead of full entities may represent a decent efficiency gain, but the speed-up could turn out to be negligible. Currently, the cache updates are managed by recipes that could be automatically generated and it is hard to see how we could achieve something similar if we used view models instead. Automapper's ProjectTo might be able to produce an Expression tree that we could usefully parse and convert into recipes for detecting the required updates.&lt;/p&gt;

&lt;p&gt;I have been able to use a list of &lt;code&gt;Include&lt;/code&gt;s to generate the SQL query necessary to make SQL Server dish up a json document containing an entity and its related entities, and I am confident that the resulting query could be used to create a computed column, and that the resulting column could be indexed in order to force SQL Server to keep the json document up to date. That would solve our slow loading problems and our cache update difficulties in exchange for slower SQL updates, and we would still need our NoSql database for smarter text queries.&lt;/p&gt;

&lt;p&gt;That said, we might decide that the web app must be usable offline, in which case we would keep enough data cached in the browser to allow us to run text search queries via javascript. This could eliminate the need for our NoSQL database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have faced some serious difficulties in our use of a NoSQL database, but I am confident that we have overcome the worst of these. There are many ways in which we could improve this architecture and I can't wait to see what we will be able to achieve.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imagining a better EntityFramework</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Sun, 23 Jun 2019 21:10:28 +0000</pubDate>
      <link>https://dev.to/jpeg729/imagining-a-better-entityframework-37ab</link>
      <guid>https://dev.to/jpeg729/imagining-a-better-entityframework-37ab</guid>
      <description>&lt;p&gt;There is a lot to like in EntityFramework... and some less desirable parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Automatic translation of C# Linq queries to SQL for efficient querying
&lt;/h3&gt;

&lt;p&gt;For example, the following asks the database to filter the books rather than loading them all and discarding the books by other authors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using anonymous objects to select only the data you need
&lt;/h3&gt;

&lt;p&gt;For example, the following only fetches the Authors.Name and Books.Title columns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorNamesAndBookTitles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;a href="https://automapper.readthedocs.io/en/latest/Queryable-Extensions.html"&gt;Automapper's ProjectTo&lt;/a&gt; to load only the data that you want
&lt;/h3&gt;

&lt;p&gt;For example, if AuthorDto contains only a subset of the properties of Author, the following will only fetch the required columns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateMap&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorsAndBooksDtos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Employees&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProjectTo&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthorDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit joins for (mostly efficient) loading of related data
&lt;/h3&gt;

&lt;p&gt;This will load all the authors along with the books each one has written.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorsWithBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatic change tracking
&lt;/h3&gt;

&lt;p&gt;Just load some data, modify it, and then call &lt;code&gt;SaveChanges()&lt;/code&gt; and all the changes get saved.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorWithBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;authorWithBooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"new name"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;authorWithBooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"book title"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automated generation of code-first migrations
&lt;/h3&gt;

&lt;p&gt;Just change your entity classes, run &lt;code&gt;Add-Migration NameOfMigration&lt;/code&gt; in the console, and a new migration class gets generated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The not so good
&lt;/h2&gt;

&lt;h3&gt;
  
  
  You can't mix returning anonymous objects and entity types
&lt;/h3&gt;

&lt;p&gt;For example, the following won't work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorNamesAndBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change tracking
&lt;/h3&gt;

&lt;p&gt;Coding a feature usually involves loading some data, verifying the state of the data, modifying the data, and maybe sending an email or generating a document. Change tracking makes this pretty easy.&lt;/p&gt;

&lt;p&gt;But if the verification part is done by a function written by a less experienced developer, you just have to hope that it doesn't modify the data. For example, the following is valid code...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but it mistakenly assigns &lt;code&gt;true&lt;/code&gt; to &lt;code&gt;author.IsActive&lt;/code&gt;, and this change will be persisted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explicit joins are inefficient when loading data from many related tables
&lt;/h3&gt;

&lt;p&gt;Unfortunately, when you include data from many related tables the query that is generated is not particularly efficient. Loading the related entities separately can often be quicker.&lt;/p&gt;

&lt;p&gt;EntityFramework.Plus provides &lt;a href="https://entityframework-plus.net/query-include-optimized"&gt;&lt;code&gt;IncludeOptimized&lt;/code&gt;&lt;/a&gt; to help with this scenario, but doesn't work with many-to-many relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Related entities can be included unexpectedly even with AsNoTracking()
&lt;/h3&gt;

&lt;p&gt;For example, this loads an author with his books and nothing else right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorAndBooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authors&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So why is &lt;code&gt;authorAndBooks.First().Author&lt;/code&gt; not null?&lt;/p&gt;

&lt;p&gt;My guess is that as EntityFramework had loaded the author into memory, it realised it could set the Author property of each book correctly from the data in cache.&lt;/p&gt;

&lt;p&gt;This could be problematic when you want to send a minimal set of data over the wire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrations
&lt;/h3&gt;

&lt;p&gt;EntityFramework's &lt;code&gt;Add-Migration&lt;/code&gt; command compares the current state of the database, the snapshot of the database shape stored in the most recent migration, and the shape of your entity classes.&lt;/p&gt;

&lt;p&gt;Hence, if you add migrations to two independent branches and then merge the result EntityFramework assumes that the least recent migration hasn't been generated nor applied. The fix is easy but tedious, you have to generate a new migration using the &lt;code&gt;-IgnoreChanges&lt;/code&gt; option in order to tell it that the current database state is good.&lt;/p&gt;

&lt;h3&gt;
  
  
  Saving untracked entities is fraught with danger
&lt;/h3&gt;

&lt;p&gt;For example, the following code duplicates the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;untrackedUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"new book title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;untrackedUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Untracked entities can come from many sources, from data sent from a client app, from a NoSQL cache, from a query with AsNoTracking, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Might there be a better way...?
&lt;/h2&gt;

&lt;p&gt;Here are a few ideas?&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrations
&lt;/h3&gt;

&lt;p&gt;An upgrade to EntityFramework Core would solve the problem, but would exchange it for another. Namely, many-to-many joins are not supported. In EntityFramework 6 you simply need ICollection properties in both classes, for example...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ICollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OnlineCourse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OnlineCourses&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OnlineCourse&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ICollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;whereas in EntityFramework Core you need to add an Enrolment entity in between them, and link Users to their Enrolments rather than directly to their OnlineCourses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Enrolment&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;OnlineCourse&lt;/span&gt; &lt;span class="n"&gt;OnlineCourse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might not be such a bad thing as it makes things more explicit. On the other hand, merging migrations is an infrequent hassle and definitely not a showstopper for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imagining a new API for writing data to the database
&lt;/h3&gt;

&lt;p&gt;EntityFramework.Plus provides a &lt;a href="https://entityframework-plus.net/batch-update"&gt;bulk update API&lt;/a&gt; that allows you to modify properties of a an entity without first loading the entities. Here is one of their examples...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UPDATE all users inactive for 2 years&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddYears&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastLoginDate&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSoftDeleted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However this API does not support linked entities.&lt;/p&gt;

&lt;p&gt;Could we create a similar API that did support linked entities? Here are a few use cases that I would like it to support...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting a singly linked property without modifying other properties of the linked entity&lt;/li&gt;
&lt;li&gt;Setting a singly linked property and simultaneously modifying other properties of the linked entity&lt;/li&gt;
&lt;li&gt;Creating a new entity and adding it to a list of linked entities on another entity&lt;/li&gt;
&lt;li&gt;Adding an existing entity to a list of linked entities on another entity, with or without modifying some of its properties.&lt;/li&gt;
&lt;li&gt;Removing an item from a list of linked entities without necessarily deleting the linked item&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe a call to our imaginary ExplicitUpdate method could return a list of modified properties with their old and new values... &lt;/p&gt;

&lt;p&gt;More details to follow...&lt;/p&gt;

&lt;h2&gt;
  
  
  What about other ORM's?
&lt;/h2&gt;

&lt;p&gt;Dapper is a well known alternative to EntityFramework with a reputation for being fast. But it is only a micro-orm which means that you don't get migrations and you have to write most of your SQL queries by hand. Now I know that I can write SQL queries that are less efficient than those that EntityFramework writes, and I am sure that I would spend weeks rewriting our queries if we decided to move to Dapper.&lt;/p&gt;

&lt;p&gt;The thing micro-orm's don't give you is easy migrations. So we would need to find another system for migrations &lt;em&gt;and&lt;/em&gt; use T4 to regenerate our entity classes every time.&lt;/p&gt;

&lt;p&gt;Micro-ORM's such as Dapper, PetaPoco, linq2db, and many others seem like decent projects, but I can't see us porting our big existing app to any of them in a hurry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jonwagner/Insight.Database/wiki"&gt;Insight.Database&lt;/a&gt; seems to be a slightly more interesting alternative.&lt;/p&gt;

&lt;p&gt;Yet another option would be to hide the database access code in an F# project and use one of their SQL Server type providers. Instead of generating model classes using T4, the compiler connects to the database and generates the required classes on the fly. We could still use EntityFramework for legacy code and for migrations, and new code could use a new data access method with very little overhead.&lt;/p&gt;

&lt;p&gt;But still, our best bet seems to be to put up with the migrations issue and to add a new API like bulk update on top of EntityFramework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Immutable data and/or an explicit write API seems to be a sensible way forward for more reliable and testable software.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The quest for the perfect software architecture</title>
      <dc:creator>jpeg729</dc:creator>
      <pubDate>Tue, 18 Jun 2019 20:58:13 +0000</pubDate>
      <link>https://dev.to/jpeg729/the-quest-for-the-perfect-software-architecture-4g98</link>
      <guid>https://dev.to/jpeg729/the-quest-for-the-perfect-software-architecture-4g98</guid>
      <description>&lt;p&gt;In this series I shall dive into topics such as ORM's, automatic data object mapping, dependency injection and other staples of modern software development. I shall examine the pros and cons of each, and consider any alternative approaches that I have been able to find.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who am I ?
&lt;/h2&gt;

&lt;p&gt;I have been working as the lead developer on a medium sized architecture for several months now. Some parts are hard to follow spaghetti code, other parts are much clearer. I worked with the previous project lead to develop a new architecture that was supposed to give us structure and help us develop faster and with fewer bugs, and yet we find it cumbersome and not entirely bug free. We suspect that it may be starting to slow us down.&lt;/p&gt;

&lt;p&gt;Maybe I am deluded, maybe I am an incorrigible dreamer, but I can't help wondering whether there isn't a better way...&lt;/p&gt;

&lt;h2&gt;
  
  
  The current architecture
&lt;/h2&gt;

&lt;p&gt;We store our data in SQL Server. The data structure is defined in C# classes that EntityFramework uses to generate the database schema and migrations.&lt;/p&gt;

&lt;p&gt;For faster loading and more advanced querying we store composite views of this data in a NoSQL database. Basically we use it as a glorified cache, and we have trouble keeping it up-to-date. &lt;/p&gt;

&lt;p&gt;The cache updates and a small number of business rules are run via code that intercepts each write operation in EntityFramework.&lt;/p&gt;

&lt;p&gt;We use HangFire to queue and run jobs that must run in the background. HangFire gives us a nice interface and automatic retries for free.&lt;/p&gt;

&lt;p&gt;The code vaguely follows a layered architecture, but the passage of father time and several interns hasn't done it any favours.&lt;/p&gt;

&lt;p&gt;Currently the app runs on a single server, serving a small number of users, but many apps do not have this luxury. This begs the question: What might we need to change in order to run at scale from the cloud?&lt;/p&gt;

&lt;h2&gt;
  
  
  In this series
&lt;/h2&gt;

&lt;p&gt;This is a provisional roadmap and may change.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;SQL ORM's and in particular the one we use: EntityFramework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Querying and reading data&lt;/li&gt;
&lt;li&gt;The poor performance of reading data from linked tables&lt;/li&gt;
&lt;li&gt;Change tracking and why it could be bad&lt;/li&gt;
&lt;li&gt;Could there be a better way?&lt;/li&gt;
&lt;li&gt;Pros and cons: the bits I like and those I would rather avoid.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NoSQL database&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use as a cache and the difficulty of keeping it up to date&lt;/li&gt;
&lt;li&gt;NoSQL vs SQL: could we have both in one storage provider?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AutoMapper&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What it can do&lt;/li&gt;
&lt;li&gt;Why is that bad?&lt;/li&gt;
&lt;li&gt;Runtime mappings vs automated code generation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dependency injection&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How we use it&lt;/li&gt;
&lt;li&gt;Why we use it and what we might &lt;em&gt;really&lt;/em&gt; need it for&lt;/li&gt;
&lt;li&gt;Double dependency trees&lt;/li&gt;
&lt;li&gt;Alternative approaches&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ideas from the world of functional programming, part 1&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immutability&lt;/li&gt;
&lt;li&gt;How to combine immutability and EntityFramework&lt;/li&gt;
&lt;li&gt;How to combine immutability and AutoMapper or its alternatives&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ideas from the world of functional programming, part 2&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fun with .Select, .SelectMany, Linq and the query syntax&lt;/li&gt;
&lt;li&gt;What should we inject and where?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reacting to changes: events, actors and stuff&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The need to react to certain types of changes&lt;/li&gt;
&lt;li&gt;How we manage it&lt;/li&gt;
&lt;li&gt;Could we use Microsoft Orleans, Akka, or something else instead?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What if we had to run at scale in the cloud?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What might we have to do differently?&lt;/li&gt;
&lt;li&gt;What might we prefer to do differently?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tying it all together&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My favourite ingredients&lt;/li&gt;
&lt;li&gt;A recipe for combining them&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(some time later) How it all turned out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The bits we liked and the bits we didn't like&lt;/li&gt;
&lt;li&gt;How we would do it if we started afresh.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
  </channel>
</rss>
