HI guys. Could you please give a little feedback on a design route I'm experimenting with.
I ditched repositories and unit of work and went with injecting the dbcontext directly into the service/application layer.
It works great. But I'm not sure if it is a sound way to do things and just needing your feedback please.
The reason this is niggling at me a little is because in the service layer I am still having to call Update and then SaveChanges according to EF requirements. So it feels like there is some coupling/dependency there even if just barely tangible.
Context (Persistence)
C#:
public class ApplicationDbContext : DbContext, IApplicationDbContext
{
private readonly ICurrentUserService _currentUserService;
private readonly IDateTimeService _dateTimeService;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IDateTimeService dateTimeService, ICurrentUserService currentUserService) : base(options)
{
_dateTimeService = dateTimeService;
_currentUserService = currentUserService;
}
public DbSet<Job> Jobs { get; set; }
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
foreach (var entry in ChangeTracker.Entries<AuditableEntity>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreatedBy = _currentUserService.UserId;
entry.Entity.Created = _dateTimeService.Now;
break;
case EntityState.Modified:
entry.Entity.LastModifiedBy = _currentUserService.UserId;
entry.Entity.LastModified = _dateTimeService.Now;
break;
}
}
var result = await base.SaveChangesAsync(cancellationToken);
return result;
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
foreach (var foreignKey in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
}
}
}
Middleware
C#:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
services.AddScoped<IApplicationDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>());
Service/Application
C#:
public class JobService : IJobService
{
private readonly IApplicationDbContext _context;
public JobService(IApplicationDbContext context)
{
_context = context;
}
public async Task<List<Job>> GetAsync()
{
return await _context.Jobs
.Include(x => x.JobType)
.ToListAsync();
}
public async Task<Job> GetByIdAsync(int id)
{
return await _context.Jobs
.Where(x => x.Id == id)
.Include(x => x.JobType)
.FirstOrDefaultAsync();
}
public async Task<Job> CreateAsync(CreateJobRequest request)
{
var entity = new Job()
{
JobNo = request.JobNo,
JobTypeId = request.JobTypeId,
StartDate = request.StartDate,
EndDate = request.EndDate,
};
_context.Jobs.Add(entity);
await _context.SaveChangesAsync();
return entity;
}
public async Task<Job> UpdateAsync(UpdateJobRequest request)
{
var entity = await _context.Jobs.FindAsync(request.Id);
entity.Id = request.Id;
entity.JobNo = request.JobNo;
entity.StartDate = request.StartDate;
entity.EndDate = request.EndDate;
entity.JobTypeId = request.JobTypeId;
_context.Jobs.Update(entity);
await _context.SaveChangesAsync();
return entity;
}
public async Task<Job> DeleteAsync(int id)
{
var entity = await _context.Jobs.FindAsync(id);
_context.Jobs.Remove(entity);
await _context.SaveChangesAsync();
return entity;
}
}