DEV Community

Myles Broomes
Myles Broomes

Posted on • Updated on

Entity Framework Core in .NET 7 7️⃣

I wanted to show a simple example of how Entity Framework Core works in .NET (specifically .NET 7 in this example). Entity Framework is what's known as an "Object-relational mapper" (or ORM for short) which allows developers to create classes that can be mapped to a database.

I've built a directory containing information about soccer players, teams, leagues and stadiums. The project (which can be found here) is a .NET core project and uses Razor Pages for the front-end views.

Below you can see a list of all of the players that have been added to the directory, and if I select "details" for one of the players, I can view further information (namely, which team they play for):

A preview of how players are listed within the application

A preview of how player information can be seen within the application

You can see how the players' Team Name matches against the name of the team in the application:

A preview of how team information can be seen within the application

In my database, I want separate tables for Teams, Players, Leagues and Stadiums so the first step is to create classes for each of those:

    public class Team
    {
        public int TeamID { get; set; }
        public string Name { get; set; }
        public int LeagueID { get; set; }
        public League League { get; set; }
        public int StadiumID { get; set; }
        public ICollection<Player> Players { get; set;}
    }
Enter fullscreen mode Exit fullscreen mode
    public class Player
    {
        public int PlayerID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int TeamID { get; set; }
        public PlayerPosition Position { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode
    public class League
    {
        public int LeagueID { get; set; }
        public ICollection<Team> Teams { get; set; }
        public int NumberOfTeams { get; set; }
        public string Name { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode
    public class Stadium
    {
        public int StadiumID { get; set; }
        public int TeamID { get; set; }
        public int Capacity { get; set; }
        public string Name { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode

The relationships of those tables is as followed:

  • One Team can have many Players

  • One Team has one Stadium

  • One League has many Stadiums

Each class has an ID property (which will represent the primary key in the database). Some classes also have an ID of another type (e.g. the Stadium class has an ID for TeamID). This represents a foreign key in the database. Also, you'll notice how the Team class contains an ICollection of type Player, and the League class contains an ICollection of type Team. When we create a class with an ICollection, the table will be represented as a one-to-many relationship in the database.

I've also created a separate class containing seed data, so we will have initial data in the database after running the application for the first time:

    public static class DbInitializer
    {
        public static void Initialize(TeamContext context)
        {
            if (context.Teams.Any())
            {
                return;
            }

            var leagues = new League[]
            {
                new League{Name="Ligue 1",NumberOfTeams=20},
                new League{Name="English Premier League",NumberOfTeams=20},
                new League{Name="La Liga",NumberOfTeams=20},
                new League{Name="Serie A",NumberOfTeams=20},
                new League{Name="Bundesliga",NumberOfTeams=18}
            };

            context.Leagues.AddRange(leagues);
            context.SaveChanges();

            var teams = new Team[]
            {
                new Team{Name="Paris Saint Germain",LeagueID=1,StadiumID=1},
                new Team{Name="Tottenham Hotspur",LeagueID=2,StadiumID=2},
                new Team{Name="Real Madrid",LeagueID=3,StadiumID=3},
                new Team{Name="AC Milan",LeagueID=4,StadiumID=4},
                new Team{Name="Bayern Munich",LeagueID=5,StadiumID=5},
                new Team{Name="Chelsea",LeagueID=2,StadiumID=6},
                new Team{Name="Internazionale",LeagueID=4,StadiumID=4}
            };

            context.Teams.AddRange(teams);
            context.SaveChanges();

            var players = new Player[]
            {
                new Player{FirstName="Lionel",LastName="Messi",TeamID=1,Position=PlayerPosition.Midfielder},
                new Player{FirstName="Harry",LastName="Kane",TeamID=2,Position=PlayerPosition.Forward},
                new Player{FirstName="Vinicius",LastName="Jr",TeamID=3,Position=PlayerPosition.Forward},
                new Player{FirstName="Rafael",LastName="Leao",TeamID=4,Position=PlayerPosition.Forward},
                new Player{FirstName="Joshua",LastName="Kimmich",TeamID=5,Position=PlayerPosition.Defender},
                new Player{FirstName="Enzo",LastName="Fernandez",TeamID=6,Position=PlayerPosition.Midfielder},
                new Player{FirstName="Lautaro",LastName="Martinez",TeamID=7,Position=PlayerPosition.Forward}
            };

            context.Players.AddRange(players);
            context.SaveChanges();                      

            var stadiums = new Stadium[]
            {
                new Stadium{Name="Parc de Princes",TeamID=1,Capacity=50000},
                new Stadium{Name="Tottenham Hotspur Stadium",TeamID=2,Capacity=60000},
                new Stadium{Name="Santiago Bernabeu Stadium",TeamID=3,Capacity=80000},
                new Stadium{Name="San Siro",TeamID=4,Capacity=75000},
                new Stadium{Name="Aliianz Arena",TeamID=5,Capacity=75000},
                new Stadium{Name="Stamford Bridge",TeamID=6,Capacity=40000}
            };

            context.Stadiums.AddRange(stadiums);
            context.SaveChanges();
        }
    }
Enter fullscreen mode Exit fullscreen mode

Once the Initialize() method is run, you can see it first checks context.Teams is populated, and if it's not (i.e. if this is the first time we're running the application) it creates several objects and saves them to the database. The TeamContext class is a class that inherits from Entity Framework's DbContext class and is used to define how we want our database to be setup. You can set which tables (DbSet) should be created from which classes and anytime we want to update our database we can access this object (e.g. in our DbInitializer above we're adding to a list then calling context.SaveChanges() to save those changes to the database.)

    public class TeamContext : DbContext
    {
        public TeamContext (DbContextOptions<TeamContext> options)
            : base(options)
        {
        }

        public DbSet<Team> Teams { get; set; }
        public DbSet<Player> Players { get; set; }
        public DbSet<League> Leagues { get; set; }
        public DbSet<Stadium> Stadiums { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Team>().ToTable("Team");
            modelBuilder.Entity<Player>().ToTable("Player");
            modelBuilder.Entity<League>().ToTable("League");
            modelBuilder.Entity<Stadium>().ToTable("Stadium");
        }
    }
Enter fullscreen mode Exit fullscreen mode

As mentioned before, we're using Razor Pages for the views. .NET makes creating the views for Create, Read, Update and Delete of entities really easy. I initially created razor views for the player entities in Visual Studio like so:

  1. Right-click on the folder where you want your views to be
  2. Hover over "Add" and select "Razor Page"
  3. Select "Razor Pages using Entity Framework (CRUD)" and hit "Add"
  4. In the dialogue that appears, set "Model Class" to whichever class you want to create razor pages for (Player in my case)
  5. Select your context class as the "DbContext class" and hit "Add"

Visual Studio will then create some razor pages for you:

Showing how Razor Pages look within the Visual Studio solution

When you run your application, you'll be able to see all of the rows from your database:

Database:
A preview of how the database tables look once created by Entity Framework

Application:

A preview of how the database tables look when presented in the application

I only wanted to give a simple preview of what can be done with Entity Framework, but if this is something that interests you and you want to go further in-depth with all the possibilities, I recommend checking out the official docs where you can also find a great tutorial which will guide you through building your very own .NET Core web application.

Top comments (1)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

I'm not saying this is a bad article. I do, however, want to highlight to newcomers that Entity Framework comes with its own demons. It is handy for sure, and what I think people love the most is that they don't have to write SQL.

All this goodness is a double edge sword, as time will demonstrate. Be ready to combine with another ORM. I personally recommend Dapper.