Entity Framework Core in .NET 7 7️⃣
Tags: dotnet, csharp, database, oop
Published: 2023-06-26 18:32:32

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](https://github.com/MylesB93/football-directory)) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnw9sk28ydtwxbdoaunh.png)

![A preview of how player information can be seen within the application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1narb0f6nxkycyvcsc0x.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po759w6txupw6jzvagtb.png)

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;}
    }
```

```
    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; }
    }
```

```
    public class League
    {
        public int LeagueID { get; set; }
        public ICollection<Team> Teams { get; set; }
        public int NumberOfTeams { get; set; }
        public string Name { get; set; }
    }
```

```
    public class Stadium
    {
        public int StadiumID { get; set; }
        public int TeamID { get; set; }
        public int Capacity { get; set; }
        public string Name { get; set; }
    }
```

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();
        }
    }
```

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");
        }
    }
```

As mentioned before, we're using [Razor Pages](https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-7.0&tabs=visual-studio) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg2lkpjuklh72czod5vz.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ic1i1eqa67a0vzv5ds6w.png)

**Application**:

![A preview of how the database tables look when presented in the application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wii5ktno2ktdjdkl4e3s.png)

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](https://learn.microsoft.com/en-us/ef/) where you can also find a great [tutorial](https://learn.microsoft.com/en-us/aspnet/core/data/ef-rp/intro?view=aspnetcore-7.0&tabs=visual-studio) which will guide you through building your very own .NET Core web application.