This is first post of Basic series where we gather everything we learned and write some code. We know theory, now it’s time for some practice. In future we will extend this sample project as new topics will arrive. For now let’s begin.
Requirements
Our client wants us to create for him simple school API. For now it should keep a list of students and let him add, update and remove students. Additionally every student can choose one Course and be assigned to it. Information kept about student should be minimalist, only Name the same about course. Client wants only to know which courses, students pick the most.
Entity Model
We start creating our project from models. We’re doing Code First so our models will be responsible for database schema. Database will be very simple. It has only two tables: Course and Student with relation one to many.
public class Course : IEntityBase
{
public int Id { get; set; }
[Required, StringLength(50)]
public string Name { get; set; }
public ICollection<Student> Students{ get; set; } = new HashSet<Student>();
}
public class Student : IEntityBase
{
public int Id { get; set; }
public int CourseId { get; set; }
[Required, StringLength(50)]
public string Name { get; set; }
public Course Course { get; set; }
}
First thing you can find interesting is that both classes implement IEntityBase. It is custom interface create by me. I like having base for entities in case I would need to add something to every entity or use polymorphism. Currently IEntityBase looks like this.
interface IEntityBase
{
int Id { get; set; }
}
It only has Id, because it’s the only thing that every entity will have right now.
Course class has 3 properties Id, Name and Students. Id and Name will be our columns. Entity Framework will create Primary Key for property with name Id, unless you specify something else to be PK. It can automatically recognize Id as the PK of this entity because its name follows the <Id>
or <classnameID>
naming convention.
Last property won’t be mapped as column. When you use another entity as property, it will tell EF that you want to create relation between both. The most common relationship one to many is made like this. Course will have many students, that’s why it has ICollection<Student>
as property. Student will have one Course, that’s why it has single Course class. Additionally we can specify Foreign Key. We need property for that in Student class (table). EF will figure that CourseId is our FK. You can specify FK yourself, if name of column will not match its destination. We’ll learn how to create many to many relationship in “Advanced” series of posts. For now, we want to KISS.
It’s worth to mention that it’s not obligatory to create property for FK, If no foreign key property is found, a shadow foreign key property will be introduced with the name <navigation property name><principal key property name>
Data Annotation
You can customize the data model by using attributes that specify formatting, validation, and database mapping rules. There are many attributes and I won’t describe it here. You should read about it from msdn page. There are multiple pages about every kind of attributes.
In our example there are two attributes above Name property. Creating table from SQL script you would need to specify column validation, size etc. EF will generate SQL for you using these attributes. Code below will create column that can’t be null and max size 50 characters.
[Required, StringLength(50)]
public string Name { get; set; }
Fluent API
Another way to customize the data model is by using Fluent API. You can do the same things as with attributes. Fluent API is more powerful, but every common action can be achieved by both. So after all both methods doesn’t differ too much. Code below will generate the same column as above example.
modelBuilder.Entity<Course>()
.Property(x => x.Name)
.HasMaxLength(50)
.IsRequired();
Data Annotation vs Fluent API
There isn’t better or worse way to customize data model, it’s up to you. Some developers don’t like to litter their models with additional logic. Some want to have entities as POCOs. That’s where Fluent API shine, because you can specify customization in another class and have your entities free of logic. Additionally using FluentAPI is cleaner, but takes more time. Single attributes won’t be a problem, on the other hand if you have a lot customization your entities would quickly end up hard to read.
DbContext
public class BlogPostContext: DbContext
{
public BlogPostContext(DbContextOptions<BlogPostContext> options) :base(options)
{
}
public DbSet<Course> Courses { get;set; }
public DbSet<Student> Students { get;set; }
}
DbContext is central place of EF. It implements repository pattern that means we can access database tables like normal list. DbContext provides abstraction for us, so we don’t need to know what’s happening under cover.
Outro
You should know concept of Entity Framework now. It is only tip of the iceberg, we will explore more about EF in future, but I still encourage you to read msdn pages about EF. We will go thru every important concept of EF, but MS did great job in their tutorial. Next time, we’ll learn how to use EF Core i.e. create, read, update and delete (CRUD) data. As always, please check other articles, and if you find this website useful share with your friends. I’m waiting for your feedback and questions.
You can find whole project here: Github or Azure DevOps in next posts I’ll describe rest of project.