Reader small image

You're reading from  Software Architecture with C# 12 and .NET 8 - Fourth Edition

Product typeBook
Published inFeb 2024
PublisherPackt
ISBN-139781805127659
Edition4th Edition
Right arrow
Authors (2):
Gabriel Baptista
Gabriel Baptista
author image
Gabriel Baptista

Gabriel Baptista has been working with software development since the beginning of .NET. Today, his main contributions are managing numerous projects for retail and industry. He is an Azure Platform-as-a-Service (PaaS) solution specialist, teaches at Computing Engineering universities, and helps tech startups as a mentor.
Read more about Gabriel Baptista

Francesco Abbruzzese
Francesco Abbruzzese
author image
Francesco Abbruzzese

Francesco Abbruzzese dedicates his life to his two great passions: software and powerlifting. He is the author of the MVC Controls Toolkit and the Blazor Controls Toolkit libraries. He has contributed to the diffusion and evangelization of the Microsoft web stack since the first version of ASP.NET. His company, Mvcct Team, offers web applications, tools, and services for web technologies. He has moved from AI systems, where he implemented one of the first decision support systems for financial institutions, to top-10 video game titles such as Puma Street Soccer.
Read more about Francesco Abbruzzese

View More author details
Right arrow

Interacting with Data in C# – Entity Framework Core

As we mentioned in Chapter 7, Understanding the Different Domains in Software Solutions, software systems are organized into layers that communicate with each other through interfaces and classes that don’t depend on how the peculiarities of each layer are implemented. When the software is a business/enterprise system, it usually contains at least three layers: the data layer, the business layer, and the presentation layer, if the software is based on a classical layer architecture (see the Classic layers architecture section of Chapter 7.

If, instead, the application is based on an onion architecture, an outermost layer contains presentation logic, drivers, and testing logic, then there is an application layer, and finally, a domain layer (see the Onion architecture section of Chapter 7). While, in the onion architecture, layers are defined in a slightly different way, the functionalities of the three layers of...

Technical requirements

This chapter requires the free Visual Studio 2022 Community Edition or better with all the database tools installed.

All the concepts in this chapter will be clarified with practical examples. You will find the code for this chapter at https://github.com/PacktPublishing/Software-Architecture-with-C-Sharp-12-and-.NET-8-4E.

Understanding ORM basics

ORMs map relational DB tables into in-memory collections of objects where object properties correspond to DB table columns. Types from C#, such as Booleans, numeric types, and strings, have corresponding DB types. If GUIDs are not available in the mapped DB, then types such as GUIDs are mapped to their equivalent string representations. All date and time types are mapped either to C# DateTime when the date/time contains no time zone information, to DateTimeOffset when the date/time also contains explicit time zone information, to DateOnly when the type contains just date information, or to TimeOnly when the type contains just time information. Any DB time duration is mapped to a TimeSpan. Finally, single characters should not be mapped at all to DB fields.

Since the string properties of most object-oriented languages have no length limits associated with them (while DB string fields usually have length limits), the DB limits are taken into account in the...

Configuring Entity Framework Core

Since, as detailed in Chapter 7, Understanding the Different Domains in Software Solutions, database handling is confined within a dedicated application layer, it is good practice to define your Entity Framework Core (DbContext) in a separate library. Accordingly, we need to define a .NET class library project.

We have two different kinds of library projects: .NET Standard and .NET Core. Please refer to Chapter 5, Implementing Code Reusability in C# 12, for a discussion on the various kinds of libraries.

While .NET libraries are tied to a specific .NET Core version, .NET Standard 2.0 libraries have a wide range of applications since they work with any .NET version greater than 2.0 and also with the old .NET Framework 4.7 and above.

Since our library is not a general-purpose library (it’s just a component of a specific .NET 8 application), instead of choosing a .NET Standard library project, we can simply choose a .NET 8 library...

Entity Framework Core migrations

Now that we’ve configured Entity Framework and defined our application-specific DbContext subclass, we can use the Entity Framework Core design tools to generate the physical database and create the database structure snapshot that’s needed by Entity Framework Core to interact with the database.

Entity Framework Core design tools must be installed in each project that needs them as NuGet packages. There are two equivalent options:

  • Tools that work in any operating system console: These are available through the Microsoft.EntityFrameworkCore.Design NuGet package. All Entity Framework Core commands are in dotnet ef ..... format since they are contained in the ef command line’s .NET Core application.
  • Tools that are specific to the Visual Studio Package Manager Console: These are contained in the Microsoft.EntityFrameworkCore.Tools NuGet package. They don’t need the dotnet ef prefix since they can only be...

Compiled models

Starting from version 6, Entity Framework Core introduced the possibility to create precompiled data structures that improve Entity Framework Core’s performance by about 10 times in the case of models with hundreds of entities (see the reference in the Further reading section for more details). This step is accomplished by generating some code that, once compiled together with the data layer project, creates data structures that our context classes can use to improve performance.

The usage of pre-compilation is advised just after you verify the system experiences slow-downs and also on very simple queries. In other words, it is better to start without pre-compilation and then possibly add it in case of slow-downs caused by the EF infrastructure.

Code is generated with the Optimize-DbContext command provided by the Microsoft.EntityFrameworkCore.Tool NuGet package that we already installed. The command accepts the folder name to place the code and the...

Querying and updating data with Entity Framework Core

To test our DB layer, we need to add a console project based on the same .NET Core version as our library to the solution. Let’s get started:

  1. Let’s call the new console project WWTravelClubDBTest.
  2. Now, we need to add our data layer as a dependency of the console project by right-clicking on the Dependencies node of the console project and selecting Add Project Reference.
  3. Remove the content of the Program.cs file and start by writing the following:
    Console.WriteLine("program start: populate database, press a key to continue");
    Console.ReadKey();
    
  4. Then, add the following namespaces at the top of the file:
    using WWTravelClubDB;
    using WWTravelClubDB.Models;
    using Microsoft.EntityFrameworkCore;
    using WWTravelClubDBTest;
    

Now that we have finished preparing our test project, we can experiment with queries and data updates. Let’s start by...

Deploying your data layer

When your database layer is deployed in production or in staging, usually, an empty database already exists, so you must apply all the migrations in order to create all the database objects. This can be done by calling context.Database.Migrate(). The Migrate method applies the migrations that haven’t been applied to the databases yet, so it may be called safely several times during the application’s lifetime.

context is an instance of our DbContext class that must be passed through a connection string with enough privileges to create tables and perform all the operations included in our migrations. Thus, typically, this connection string is different from the string we will use during normal application operations.

During the deployment of a web application on Azure, we are given the opportunity to check migrations with a connection string we provide. We can also check migrations manually by calling the context.Database.Migrate() method...

How data and domain layers communicate with other layers

As discussed in Chapter 7, Understanding the Different Domains in Software Solutions, classical layer architectures use plain objects and repositories to communicate with the other layers.

Therefore, the entities that define Entity Framework Core configuration themselves can be used as they are to communicate with other layers, since they are just record-like lists of public properties, as prescribed for plain objects.

The case of domain layers and onion architectures is slightly more complex, since, in this case, the domain layer communicates with the application layer through rich objects whose methods represent application domain rules. Accordingly, in general, the remainder of the application can’t access all domain layer objects’ properties but is forced to modify them through their own methods, in order to enforce domain rules.

In other words, Entity Framework entities are record-like lists of...

Understanding Entity Framework Core advanced features

An interesting Entity Framework advanced feature that is worth mentioning is global filters, which were introduced at the end of 2017. They enable techniques such as soft delete and multi-tenant tables that are shared by several users, where each user just sees its records.

Global filters are defined with the modelBuilder object, which is available in the DbContext OnModelCreating method. The syntax for this method is as follows:

modelBuilder.Entity<MyEntity>().HasQueryFilter(m => <define filter condition here>);

For instance, if we add an IsDeleted property to our Package class, we may soft delete a Package without removing it from the database by defining the following filter:

modelBuilder.Entity<Package>().HasQueryFilter(m => !m.IsDeleted);

However, filters contain DbContext properties. Thus, for instance, if we add a CurrentUserID property to our DbContext subclass (whose value...

Summary

In this chapter, we looked at the essentials of ORM basics and why they are so useful. Then, we described Entity Framework Core. In particular, we discussed how to configure database mappings with class annotations and other declarations and commands that are included in DbContext subclasses, and in configuration classes associated with each entity.

Then, we discussed how to create data structures for improving ORM performance and how to automatically create and update the physical database with the help of migrations, as well as how to query and pass updates to the database through Entity Framework Core. Finally, we learned how to pass direct SQL commands and transactions through Entity Framework Core, as well as how to deploy a data layer based on Entity Framework Core.

This chapter also reviewed some advanced features that were introduced in the latest Entity Framework Core releases.

In the next chapter, we move on to microservices orchestrators and will learn...

Questions

  1. How does Entity Framework Core adapt to several different database engines?
  2. How are primary keys declared in Entity Framework Core?
  3. How is a string field’s length declared in Entity Framework Core?
  4. How are indexes declared in Entity Framework Core?
  5. How are relations declared in Entity Framework Core?
  6. What are the two important migration commands?
  7. By default, are related entities loaded by LINQ queries?
  8. Is it possible to return database data in a class instance that isn’t a database entity? If yes, how?
  9. How are migrations applied in production and staging?

Further reading

Learn more on Discord

To join the Discord community for this book – where you can share feedback, ask questions to the authors, and learn about new releases – follow the QR code below:

https://packt.link/SoftwareArchitectureCSharp12Dotnet8

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Software Architecture with C# 12 and .NET 8 - Fourth Edition
Published in: Feb 2024Publisher: PacktISBN-13: 9781805127659
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (2)

author image
Gabriel Baptista

Gabriel Baptista has been working with software development since the beginning of .NET. Today, his main contributions are managing numerous projects for retail and industry. He is an Azure Platform-as-a-Service (PaaS) solution specialist, teaches at Computing Engineering universities, and helps tech startups as a mentor.
Read more about Gabriel Baptista

author image
Francesco Abbruzzese

Francesco Abbruzzese dedicates his life to his two great passions: software and powerlifting. He is the author of the MVC Controls Toolkit and the Blazor Controls Toolkit libraries. He has contributed to the diffusion and evangelization of the Microsoft web stack since the first version of ASP.NET. His company, Mvcct Team, offers web applications, tools, and services for web technologies. He has moved from AI systems, where he implemented one of the first decision support systems for financial institutions, to top-10 video game titles such as Puma Street Soccer.
Read more about Francesco Abbruzzese