In previous article, we have developed a blog management schema using EF core. Now, let’s try to create a simple class which performs CRUD operations.
Before we begin
Generally, when apps use Entity Framework core, two patterns are very prominent in those solutions:
These two patterns are to optimize the round trips from .NET CLR to SQL and to avoid the repetitive code. In this article, we are not going to talk about these patterns. Only focus of this article is to understand how CRUD operations can be performed on EF core models using a simple class.
So, for following steps, create a class library Blog.Data and add reference to Blog.Data.EF (which contains blog management EF core models).
Now add some new class to Blog.Data:
We will try to add some code now. Let’s start with the main entity, Posts, which contain more fields and relationships as compared to other entities.
In each of these classes, create a constructor and inject BlogContext object in that constructor. All these data access layer classes would hold this reference of context for implementing CRUD operations.
Entity framework core context (i.e. BlogContext in our case) keeps track of whether the entities which are in memory are in sync with the corresponding rows in the database.
An application can perform different operations, like adding a new entity in DbSet collection or removing an entity from the DbSet collection, etc. After performing such operations, generally the application is supposed to call SaveChanges (or SaveChangesAsync) to persist the modifications in database.
Depending on operations performed, entities may be in one of the states. This state defines which SQL statements would be issued by entity framework.
- Added, when entity does not exist in database. In this case, INSERT statement is issued by SaveChanges method.
- Modified, when an entity exists in database, but one or more properties have been modified by application. In this case, UPDATE statement is issued by SaveChanges method.
- Deleted, entity exists in database, but it has been marked for deletion. In this case, DELETE statement is issued by SaveChanges method.
- Unchanged, as the name suggests, no changes were applied to the entity and all of its properties are same as they are in corresponding row in database table. When an entity is read from database, it is in this state.
- Detached, context does not track such objects.
These state changes are transparent to the application. Entity framework core takes care of changing states automatically.
Next few sections just describe how to read and modify entities and then call SaveChanges method to persist the modifications.
Below snippet shows data access class, PostsDataAccess, which shows CRUD operations implemented for Posts entity.
Some important methods which are used in below code snippet but not discussed yet are:
- AsNoTracking, this can be used to tell EF core not track those entities.
- Add or AddAsync, this adds a new object making its state to be Added.
- Update, this marks the object for modification.
- Remove, this marks object for deletion.
How to verify ?
We have created a class library for EF core models and another class library for performing CRUD operations. There is no main method. So how can we verify that the above code is working ?
One way is, we can create a console application and add references of these two class libraries and then call data access layer methods.
Better approach probably, is to create unit tests and call the data access methods. I would prefer creating xUnit tests, as in coming articles, we are going to create APIs required for blog management system. If we decide to write unit tests, we can use In-Memory database provider instead of using actual SQL Server database.
In this article, we have created methods for Posts data access. Similarly, methods for Categories, Tags, Comments can also be created easily. But you can easily notice, that most of the data access classes would have similar code for CRUD operations, the only difference between different data access classes is that each of them is targeting different entities.
To avoid such duplication of code, generally repository pattern is used. Let’s discuss about repository pattern in next article.
I hope you find this information useful. Let me know your thoughts.