The DbContext class provided by EF Core is designed to work as a Unit Of Work (https://martinfowler.com/eaaCatalog/unitOfWork.html) that stores and tracks all the objects in the model. As a Unit Of Work, DbContext lets you add an object for tracking, and then we set the EntityState parameter of the object so that DbContext can perform the correct database operation (INSERT, UPDATE, or DELETE) when needed—that is, when calling the Save() or SaveAsync() methods.
When defining your instance of DbContext, you added properties of the DbContext type for each entity you wanted your model to include. The DbContext is a special type of collection that is aware of the EntityState objects, and lets you control them with simple methods such as Add() or Remove().
Here is an example of how products are added in the GiveNTake application:
//ProductsController.cs
[HttpPost("")]
public async Task<IActionResult> AddNewProduct([FromBody] NewProductDTO newProduct)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Category category = GetProduct(newpProduct.Category, newProduct.Subcategory);
City city = GetCity(newProduct.City);
User owner = await _context.Users.FindAsync("[email protected]"),
var product = new Product()
{
owner = owner,
Category = category,
Title = newProduct.Name,
Description = newProduct.Description,
City = city,
PublishDate = DateTime.UtcNow
};
_context.Products.Add(product);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetProduct),
new { id = product.ProductId },
...);
}
The method does some validation checks and then fetches some related entities (we will see how to create entity relationships later in this chapter). Then, a new instance of the Product entity is created. At this stage, the object is detached from DbContext, which means EF Core doesn't know of its existence. The _context.Products.Add(product) call attaches the new product to DbContext so that it will be tracked. Since we used the Add() method, the entity state is now added, and therefore, the call to _context.SaveChangesAsync() generates an INSERT statement.