The first thing we will do is to add a new Class library project called ProjectManagement.Domain
to our solution.
So, let’s open our solution folder in the terminal:
dotnet new classlib -n ProjectManagement.Domain dotnet sln add ProjectManagement.Domain
With the first command, we create a new Class library project inside our solution’s folder. Then, with the second one we add the project to our solution. Alternatively, you can use the UI of your IDE to replicate the above process.
Once the project is created, let’s create a new folder inside it and name it Models
. In this folder, we’ll store the entities around which, our project management application will revolve.
Let’s create the Project
and Subtask
entities in separate files:
public class Project { public Guid Id { get; set; } public required string Name { get; set; } public required string Description { get; set; } public ICollection<Subtask> Subtasks { get; set; } = []; }
public class Subtask { public Guid Id { get; set; } public required string Title { get; set; } public required string Description { get; set; } public required bool IsCompleted { get; set; } public Guid ProjectId { get; set; } public Project? Project { get; set; } }
Both classes have an Id
property which we’ll use to identify the different projects and their subtasks. They also have other properties most of which will be mapped to corresponding database table columns. The Subtasks
property in the Project
class and the Project
property in the Subtask
class are what we call navigational properties – they define the relationships between the two entities.
Now, let’s define some restrictions for the properties of our classes.
Let’s start by creating a new Class Library project called ProjectManagement.Infrastructure
. Next, we right-click on the ProjectManagement.Infrastructure
project, navigate to Add
, then pick Project Reference
and select the ProjectManagement.Domain
project.
Alternatively, we can use the CLI:
dotnet new classlib -n ProjectManagement.Infrastructure dotnet sln add ProjectManagement.Infrastructure dotnet add ProjectManagement.Infrastructure reference ProjectManagement.Domain
We are already familiar with the first two commands – they are used to create a new project and to add it to our solution. The final command adds a reference to the ProjectManagement.Domain
project inside the ProjectManagement.Infrastructure
project.
After this is done, let’s open the ProjectManagement.Infrastructure
project in the terminal and add one package:
dotnet add package Microsoft.EntityFrameworkCore --version 9.0.0
We install thе Microsoft.EntityFrameworkCore
inside the ProjectManagement.Infrastructure
project. Depending on your preferences, you can do this via the Package Manager or the NuGet user interface.
Next, let’s create a new folder in our project called Configurations
where we will add the ProjectConfiguration
and SubtaskConfiguration
classes:
public class ProjectConfiguration : IEntityTypeConfiguration<Project> { public void Configure(EntityTypeBuilder<Project> builder) { builder.HasKey(p => p.Id); builder.Property(p => p.Name) .IsRequired() .HasMaxLength(30); builder.Property(p => p.Description) .IsRequired() .HasMaxLength(120); } }
public class SubtaskConfiguration : IEntityTypeConfiguration<Subtask> { public void Configure(EntityTypeBuilder<Subtask> builder) { builder.HasKey(st => st.Id); builder.Property(st => st.Title) .IsRequired() .HasMaxLength(30); builder.Property(st => st.Description) .IsRequired() .HasMaxLength(120); builder.Property(st => st.IsCompleted) .IsRequired(); // Configure relationship with Project builder.HasOne(st => st.Project) .WithMany(p => p.Subtasks) .HasForeignKey(st => st.ProjectId) .IsRequired(); } }
Inside the folder, we create the ProjectConfiguration
and SubtaskConfiguration
classes. Both implement the IEntityTypeConfiguration<TEntity>
interface where TEntity
is the corresponding data class. The interface requires us to implement the Configure()
method.
Inside this method, we configure our various restrictions on the entities, such as what property will be the key for each table (in our case, we can skip this as Entity Framework is smart enough to mark any property named Id
as the key), which properties are required, and what is the maximum character length where applicable.
Inside the SubtaskConfiguration
class, we also define the relationship between the two entities by specifying that each subtask can have only one project associated with it, but that a project can have many related subtasks. Finally, we define that the foreign key for the Subtasks
table will be the ProjectId
column.
In the next lesson, we’ll define our database context class and apply our configurations.