Telerik blogs
How ToT2 Dark_1200x303

Object Relational Mapping is very common in web development, especially when there is a database involved because an ORM makes the development work much easier. In this article, we will see what an ORM is and how to implement it in a .NET application.

The Object Relational Mapping (ORM) subject is very well known in the .NET web development environment and is very likely to be a requirement in a job offer in the area. That’s why it’s important that developers learn about this concept—the implementation and maintenance of a database become simpler and faster with the use of an ORM.

What Is ORM (Object Relational Mapping)?

Object Relational Mapping, also known as Mapping Tool, in computer science is a programming technique used to convert data between systems of incompatible types through object-oriented programming languages.

In simple terms, it is as if the ORM creates a “virtual database” and reflects this “virtual database” in a traditional database, such as SQL Server for example.

Why Is ORM Useful?

The main advantage of using ORMs is saving time on development and eliminating the need to repeat SQL code.

Another important advantage is the traceability of changes made to the database. There are libraries specialized in ORMs that record the entire history of the data from its creation to the last changes.

ORM in the .NET Context

It is very common to find .NET applications that make use of some type of ORM, whether created by the developer or using some tool.

Therefore, ORM is an important subject for .NET programmers to learn and is almost always covered in interviews for positions in the field.

There are currently several libraries that implement ORMs available for working with .NET. Some are open source while others are paid, in addition to having functions for the most varied needs. Something common among developers is the discussion about which is the best ORM, but the truth is that it is not possible to estimate which is the best, as it will depend on the needs of each scenario.

The Entity Framework Core

As said before, it is almost impossible to indicate which would be the best ORM, but probably the best known is the Entity Framework Core, or simply EF Core.

EF Core is a lightweight, extensible, open-source, cross-platform version of the popular Entity Framework data access technology, developed and maintained by Microsoft for the .NET platform.

EF Core allows .NET developers to implement a database using objects. It also eliminates the need for most SQL code that normally needs to be configured in “Database First” approaches. EF Core also supports several database engines including SQL Server, SQLite, MySQL and many others—you can check the complete list at this link: Database Providers.

EF Core vs. EF6

Unsurprisingly, the nomenclature used by Microsoft can sometimes be a little confusing, but, as always, everything is explained clearly. In the context of Entity Framework, there are two major versions—one is Entity Framework Core (EF Core) and the other is Entity Framework 6 (EF6).

As seen earlier, EF Core is a modern object database mapper for .NET, whereas EF6 is an object-relational mapper designed for .NET Framework but with support for .NET Core.

In simple terms, EF Core is used for modern applications, while EF6 is recommended for legacy applications where the framework was developed in .NET Framework, the first version of .NET.

For a more detailed view of the subject, I recommend reading this article on the official Microsoft website: EF Core and EF6.

Implementing EF Core in an ASP.NET Core Application

In this article, we will create a minimal API to demonstrate the use of the Entity Framework Core together with the SQLite database.

The minimal API is a feature available from .NET 6 onward. To create the project, you can use the code below, then open the project with your favorite IDE (this example uses Visual Studio 2022).

You can access the complete source code of the final project at this link: Source Code.

Get the .NET Core CLI Tools

First of all, you need to install the EF Core CLI, it can be installed locally or globally, most developers prefer to install it in global mode. For that use the command below:

dotnet tool install --global dotnet-ef

Structuring the Database

Our database will have the following structure:

Table Structure

dotnet new web -o BlogManager

Creating the Model Classes

First, we will create the model classes. So, create a new folder called “Models,” and inside it create the following classes:

Author

namespace BlogManager.Models;

public record Author
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string EmailAddress { get; set; }
}

Tag

namespace BlogManager.Models;

public record Tag
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid BlogPostId { get; set; }
}

BlogPost

namespace BlogManager.Models;

public record BlogPost
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public List<Tag> Tags { get; set; }
    public DateTime PublishedDate { get; set; } = DateTime.Now;
    public Guid AuthorId { get; set; }
    public string CoverImage { get; set; }
    public Author Author { get; set; }
}

BlogPostDto

namespace BlogManager.Models;
public record BlogPostDto(Guid Id, string Title, string Content, List<Tag> Tags, DateTime PublishedDate, string CoverImage, Author Author);

Downloading the Dependencies

To download the necessary dependencies, double click on the project file (.csproj) and add the code below:

 <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" />
	<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

Creating the Context Class

Next, we will create the class responsible for implementing the database context settings. Create a new folder called “Data” and inside it the following class:

AppDbContext

using BlogManager.Models;
using Microsoft.EntityFrameworkCore;

namespace BlogManager.Data;

public class AppDbContext : DbContext
{
    public DbSet<BlogPost>? Posts { get; set; }

    public DbSet<Tag>? Tags { get; set; }

    public DbSet<Author>? Authors { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("DataSource = blogdb.db; Cache=Shared");
}

Running EF Core Commands

Our data modeling is ready, represented by the Model classes. Our database will reflect these classes, the entire database, and the tables creation script. These will be created through some commands that are available in the EF Core library.

To execute the commands, you can open the Visual Studio console by right-clicking on the project and choosing the option: “Open in Terminal.” You can also execute the commands through the terminal of your machine at the root of the project.

You can first run the command below:

dotnet ef migrations add InitialModel

The “dotnet ef migrations add” command creates the EF Core model from the domain (entity) classes and migrations will create or update the database schema based on the EF Core model.

In simple terms, EF Core will create a new folder called “Migrations” and inside it will contain the files responsible for applying the creations and changes regarding the database with all the relationships between the entities, based on the Model classes we created in the project.

Then we will execute the command responsible for applying the script created with the previous command and performing the creations and changes.

So, run the command below:

dotnet ef database update

Note that the previous command created a database—as we are using SQLite, a file with the extension .db was created at the root of the project. In this article, we will use the SQLite View Editor available for free on the Microsoft Store if you use Windows, but you can use any other.

Database Created

In the image below we can see in the SQL Viewer Editor the structure of the tables generated after applying the EF Core commands:

Database Viewer

Performing CRUD Operations With EF Core

Now we just need to add the configurations of the main classes and add the methods responsible for CRUD. For that, in the Program class, replace the existing code with the code below:

using BlogManager.Data;
using BlogManager.Models;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

RegisterServices(builder.Services);

var app = builder.Build();

ConfigureApp(app);

void ConfigureApp(WebApplication app)
{
    var ctx = app.Services.CreateScope().ServiceProvider.GetService<AppDbContext>();
    ctx.Database.EnsureCreated();

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    app.UseHttpsRedirection();

    app.UseAuthorization();

    app.MapControllers();

    app.UseCors(builder => builder.AllowAnyOrigin());
}

void RegisterServices(IServiceCollection services)
{
    // Add services to the container.
    services.AddDbContext<AppDbContext>();

    services.AddControllers();
    services.AddEndpointsApiExplorer();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "Blogs API",
            Description = "Blog administration",
            Version = "v1"
        });
    });
}

app.MapGet("/v1/posts", (AppDbContext context) =>
{
    var posts = context.Posts;

    if (!posts.Any())
        return Results.NotFound();

    var postsDto = posts.Select(b => new BlogPostDto(b.Id, b.Title, b.Content, b.Tags, b.PublishedDate, b.CoverImage, b.Author)).ToList();

    return Results.Ok(postsDto);

}).Produces<BlogPostDto>();

app.MapPost("/v1/posts", (BlogPostDto createBlogPost, AppDbContext context) =>
{
    try
    {
        var post = new BlogPost()
        {
            Id = Guid.NewGuid(),
            Title = createBlogPost.Title,
            Content = createBlogPost.Content,
            Tags = createBlogPost.Tags,
            PublishedDate = DateTime.UtcNow,
            CoverImage = createBlogPost.CoverImage,
            Author = createBlogPost.Author
        };

        context.Add(post);
        context.SaveChanges();

        return Results.Created($"v1/posts/{createBlogPost.Id}", createBlogPost);
    }
    catch (Exception ex)
    {
        return Results.BadRequest(ex);
    }
}).Produces<BlogPostDto>();

app.MapPut("/v1/posts", (Guid id, BlogPost updateBlogPost, AppDbContext context) =>
{
    try
    {
        var blogPost = context.Posts.Find(id);

        if (blogPost is null)
            return Results.NotFound();

        context.Entry(blogPost).CurrentValues.SetValues(updateBlogPost);
        context.SaveChanges();

        return Results.NoContent();
    }
    catch (Exception ex)
    {
        return Results.BadRequest($"Error ocurred while puting to Post: {ex.Message}");
    }
});

app.MapDelete("/v1/posts", (Guid id, AppDbContext context) =>
{
    try
    {
        var post = context.Posts.Where(p => p.Id == id).FirstOrDefault();

        if (post is null)
            return Results.BadRequest($"Post not found to Id = {id}");

        context.Remove(post);
        context.SaveChanges();

        return Results.NoContent();
    }
    catch (Exception ex)
    {
        return Results.BadRequest(ex);
    }
});

app.Run(); 

Note that the “ConfigureApp” and “RegisterServices” methods are doing the main configurations of the classes, as well as configuring Swagger to display the API interface.

The remaining methods are responsible for operations on the database—to fetch and persist. Note that EF Core has very simple methods to perform these operations such as “Add” to create a new record and “SaveChanges” to save.

In other words, EF Core is a very robust, complete and simple-to-use library.

You can run the project and test all the functions. Below is an example image of the Get function of the records in the database by Fiddler Everywhere (a secure web debugging proxy for macOS, Windows and Linux.).

Get Post

Conclusion

In this article, we saw the importance of using an ORM and how to implement it in practice in an ASP.NET Core application. There are several libraries that support the creation of ORMs. In this article, we covered one of the best known—EF Core.

Despite the advantages of using an ORM, it may not always be the best choice. Everything will depend on the needs of each scenario.


assis-zang-bio
About the Author

Assis Zang

Assis Zang is a software developer from Brazil, developing in the .NET platform since 2017. In his free time, he enjoys playing video games and reading good books. You can follow him at: LinkedIn and Github.

Related Posts

Comments

Comments are disabled in preview mode.