DotNetStories
Many developers when building multi-tier, multi-layered
application use patterns to enhance the testability and
usability of their apps. They often use
UoW and Repository patterns which in
general are great patterns to use.
For example,
in the case of the repository pattern, the purpose is to
abstract away the
low-level database query logic.
Developers used to write SQL statements in their
code and the repository pattern was a way to move that SQL
out of individual methods scattered throughout the code
base.
Developers building applications with
ASP.Net Core and Entity Framework Core should not use UoW
and Repository pattern anymore. EF Core supports unit
testing and mock contexts.
EF Core is 100% test-friendly, one can even mock what e.g SaveChanges method (returns the count of records that were affected) returns.
It also supports injecting the database context into the web
request by using a
service that uses Dependency Injection.
In a nutshell, Entity
Framework already implements a repository
pattern. DbContext is the UoW (Unit of
Work) and each DbSet is the repository. By
implementing another layer on top of this, is not only
redundant, but makes maintenance much more harder.
Let's ask ourselves. What is DbContext? It is a class. This is a no-brainer. It is a class that contains multiple properties, each implementing IDbSet. IDbSet is the same thing as IRepository.
It contains methods to Add, Delete etc. It also implements IQueryable – so you have the whole LINQ query set including things like First, Single, Where.
The example below demonstrates how to add an Entity
Framework Core database context as a service using
Dependency Injection in an
ASP.Net MVC Core 3.1 application. These are
just snippets and not the whole codebase.
We will
also demonstrate how to reference the database context from
an MVC Controller.
We need to have a connection string e.g DefaultConnection. This is confugured in the appsettings.json, appsettings.Development.json files.
In this example the database server is SQL Server.
You
also need to install
Microsoft.EntityFrameworkCore.SqlServer
Nuget package.
Model/ViewModel class:
public class Customer {
[Key]
public int Id { get; set; }
public String FullName { get; set; }
}
DBContext class:
public class ModelContext : DbContext {
public ModelContext(DbContextOptions<ModelContext>
options) : base(options) {}
public DbSet<Customer> Customers { get; set; }
}
We now need to set up
dependency injection by configuring the
Startup.cs file:
public void
ConfigureServices(IServiceCollection services) {
services.AddDbContext<ModelContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
}
Now we need to make
DBContext accessible from within each
controller e.g CustomerController through
the constructor. See below (just snippet)
public class CustomerController: Controller
{
private readonly ModelContext _context;
public
CustomerController(ILogger<CustomerController>
logger, ModelContext context)
{
_logger = logger;
_context = context;
}
public IActionResult Index() {
List<Customer> AllCustomers =
_context.Customers.ToList();
return View(AllCustomers);
}
}
To recap, when writing code try to avoid needless complexity
by over-engineering things.
Getting data from
the database is a common operation and by adding additional
layers of abstractions usually only makes it much harder to
maintain the code.
Comments have been disabled for this content.