We will perform CRUD operations on our ToDo
model using the Entity Framework DbContext
class.
Tip
It doesn't matter which approach we select to create the database and conceptual model (Database First, Code First, or Model First); from the code perspective, it's the same code that the developers need to write in order to use Entity Framework.
Now let's say we have a model for our ToDo item, that is, ToDo
. We also have the DbContext
class created to perform CRUD operations on the ToDo
model. Let's take a look at how we can use Entity Framework to perform CRUD operations on our ToDo
model. The important thing to note in these examples would be the use of LINQ. We will write all our queries in LINQ, and Entity Framework will take care of converting it to the appropriate SQL and return the results.
The way Entity Framework works is that using the DbContext
class, we can retrieve all the data by simply accessing the model collection associated with the view. So, to fetch a list of items, we just need to get the model collection from the context class:
using(ToDoDBEntities db = new ToDoDBEntities()) { IEnumerable<ToDo> todoItems = db.ToDos; }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities();
We then used the
DbContext
object to fetch theToDo
entities:IEnumerable<ToDo> todoItems = db.ToDos;
After this call, the list of ToDo items will be available in the ToDo items collection if we enumerate ToDo items. Entity Framework will internally perform the following activities for us to fetch the result:
Parsed our request for the data.
Generated the needed SQL query to perform this action.
Used the context class to wire up the SQL to the database.
Fetched the results from the database.
Created the strongly typed models from the retrieved results and return them to the user.
If we want to retrieve a single item from the model collection, we have many ways of doing it. Typically, we can use any LINQ function to fetch the single record from the model collection. Also, if we want to fetch the result using the primary key, we can use the Find
method to do it. Let's look at a few ways in which we can retrieve a single item using Entity Framework:
using (ToDoDBEntities db = new ToDoDBEntities()) { ToDo todo1 = db.ToDos.Find(id); ToDo todo3 = db.ToDos.FirstOrDefault(item => item.TodoItem == "Test item"); ToDo todo2 = db.ToDos.SingleOrDefault(item => item.TodoItem == "Test item"); }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities()
Retrieved an item by passing the key values, that is, using the
Find
function:ToDo todo1 = db.ToDos.Find(id);
Retrieved an item by passing a non-key value using the
FirstOrDefault
function:ToDo todo2 = db.ToDos.SingleOrDefault(item => item.TodoItem == "Test item");
Retrieved an item by passing a non-key value using the
SingleOrDefault
function:ToDo todo2 = db.ToDos.SingleOrDefault(item => item.TodoItem == "Test item");
Tip
The
FirstOrDefault
andSingleOrDefault
functions will return the first occurrence of the item if it is found, else it will returnnull
. We should always check for the null values before using the item retrieved using these functions.SingleOrDefault
will throw an exception if it finds multiple items matching the request criteria.
To create an item, we simply need to create the model, assign the values in the model properties, and then call the SaveChanges
method on Entity Framework. Now let's see how we can create a ToDo item using Entity Framework:
using (ToDoDBEntities db = new ToDoDBEntities()) { ToDo todoItem = new ToDo(); todoItem.TodoItem = "This is a test item."; todoItem.IsDone = false; db.ToDos.Add(todoItem); db.SaveChanges(); }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities()
Created a new ToDo item:
ToDo todoItem = new ToDo();
Populated the ToDo item properties with the desired values:
todoItem.TodoItem = "This is a test item."; todoItem.IsDone = false;
Added the item to the context class:
db.ToDos.Add(todoItem);
Called Entity Framework's
SaveChanges
method to persist these changes in the database:db.SaveChanges();
To update an existing item, there are two possibilities. The first possibility is that we will fetch the model, update some of the properties of the model, and then save the updated model in the database. To do this, we just need to fetch the required model using the DbContext
class, update its properties, and then call the SaveChanges
method on the DbContext
object. Let's try to update a model with the ID 3
:
using (ToDoDBEntities db = new ToDoDBEntities()) { int id = 3; ToDo todo = db.ToDos.Find(id); todo.TodoItem = "This has been updated"; todo.IsDone = false; db.SaveChanges(); }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities()
Fetched the item with
id = 3
:int id = 3; ToDo todo = db.ToDos.Find(id);
Updated the model properties:
todo.TodoItem = "This has been updated"; todo.IsDone = false;
Called Entity Framework's
SaveChanges
method to persist these changes in the database:db.SaveChanges();
What is happening in the preceding code is that the DbContext
class was still in scope when the entity was being updated and saved. The DbContext
class is able to track the changes in the entity if it is in scope. However, this approach is rarely useful, because in real applications in a typical n-tier application, the entities will be passed through multiple layers, and any layer can update this entity, and at the time of updating the entity, objects are usually disconnected from the context.
So to perform the updates in such a disconnected environment, we need to attach the updated entity back to let the DbContext
class identify the modifications made in the entity, and then generate the appropriate update SQL accordingly and persist the updates in the database. This can be done by attaching the entity back to the DbContext
class. Let's see how a ToDo
model can be attached to the DbContext
class if it is being passed from a different tier:
using (ToDoDBEntities db = new ToDoDBEntities()) { db.Entry(todo).State = EntityState.Modified; db.SaveChanges(); }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities()
Attached the model to the
DbContext
class and marked this model as modified:db.Entry(todo).State = EntityState.Modified;
Called Entity Framework's
SaveChanges
method to persist these changes in the database:db.SaveChanges();
To delete an item, we just need to fetch the item that needs to be deleted, call the Remove
method on the model collection, and call the SaveChanges
method on the DbContext
class. Let's try to delete a model with the ID 3
:
using (ToDoDBEntities db = new ToDoDBEntities()) { int id = 3; ToDo todo = db.ToDos.Find(id); db.ToDos.Remove(todo); db.SaveChanges(); }
Let's try to understand the preceding code:
We created an object of the
DbContext
class:ToDoDBEntities db = new ToDoDBEntities()
Fetched the item with
id = 3
:int id = 3; ToDo todo = db.ToDos.Find(id);
Removed the item from the collection:
db.ToDos.Remove(todo);
Called Entity Framework's
SaveChanges
method to persist these changes in the database:db.SaveChanges();