Let's suppose I have 2 repositories
:
- first is responsible for creating job and return
jobId
- second is responsible for creating log and take
jobId
as argument
My goal is to:
- save
Job
andLog
simultaneously - prevent situation when in case of error only
Job
would be saved withoutLog
What is the most recommended way to get desired result?
I prepared 3 cases which came to my mind but if you see better alternative please share it.
- option 1 (getting result and save changes in controller)
public class JobRepository : IJobRepository
{
private readonly Context _context;
public JobRepository(Context context)
{
_context = context;
}
public Guid CreateJob()
{
var job = new Job { Id = Guid.NewGuid() };
_context.Jobs.Add(job);
return job.Id;
}
}
// ...
public class LogRepository : ILogRepository
{
private readonly Context _context;
public LogRepository(Context context)
{
_context = context;
}
public void CreateLog(Guid id)
{
var log = new Log { Jobid = id };
_context.Logs.Add(log);
}
}
// ...
public class JobsController : Controller
{
private readonly Context _context;
private readonly IJobRepository _jobRepository;
private readonly ILogRepository _logRepository;
public JobsController(Context context, JobRepository jobRepository, ILogRepository logRepository)
{
_context = context;
_jobRepository = jobRepository;
_logRepository = logRepository
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create()
{
var id = _jobRepository.CreateJob();
_logRepository.CreateLog(id);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
- option 2 (inject one repository into another)
public class JobRepository : IJobRepository
{
private readonly Context _context;
private readonly ILogRepository _logRepository;
public JobRepository(Context context, ILogRepository logRepository)
{
_context = context;
}
public void CreateJob()
{
var job = new Job { Id = Guid.NewGuid() };
_context.Jobs.Add(job);
_logRepository.CreateLog(job.Id);
_context.SaveChanges();
}
}
// ...
public class LogRepository : ILogRepository
{
private readonly Context _context;
public LogRepository(Context context)
{
_context = context;
}
public void CreateLog(Guid id)
{
var log = new Log { Jobid = id };
_context.Logs.Add(log);
}
}
// ...
public class JobsController : Controller
{
private readonly IJobRepository _jobRepository;
public JobsController(JobRepository jobRepository)
{
_jobRepository = jobRepository;
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create()
{
_jobRepository.CreateJob();
return RedirectToAction("Index");
}
}
- option 3 (do not use context in controller but declare
Save
method in each repo)
public class JobRepository : IJobRepository
{
private readonly Context _context;
public JobRepository(Context context)
{
_context = context;
}
public Guid CreateJob()
{
var job = new Job { Id = Guid.NewGuid() };
_context.Jobs.Add(job);
return job.Id;
}
public void Save()
{
_context.SaveChanges();
}
}
// ...
public class LogRepository : ILogRepository
{
private readonly Context _context;
public LogRepository(Context context)
{
_context = context;
}
public void CreateLog(Guid id)
{
var log = new Log { Jobid = id };
_context.Logs.Add(log);
}
public void Save()
{
_context.SaveChanges();
}
}
// ...
public class JobsController : Controller
{
private readonly IJobRepository _jobRepository;
private readonly ILogRepository _logRepository;
public JobsController(JobRepository jobRepository, ILogRepository logRepository)
{
_jobRepository = jobRepository;
_logRepository = logRepository
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create()
{
var id = _jobRepository.CreateJob();
_logRepository.CreateLog(id);
return RedirectToAction("Index");
}
}
CodePudding user response:
As the use case suggests that the operations (saving and logging) should happen as a single unit of work.
I would suggest an approach similar to the third one. But instead of directly injecting both the repositories into the controller. We could create a service that would then make use of the repositories.
Here we can create a service as follows :
public class JobService : IJobService
{
private readonly IJobRepository _jobRepo;
private readonly ILogRepository _logRepo;
public JobRepository(IJobRepository jobRepo, ILogRepository logRepo)
{
_jobRepo = jobRepo;
_logRepo = logRepo;
}
public void CreateJob()
{
var id = _jobRepo.CreateJob();
_logRepo.CreateLog(id);
}
}
public class JobsController : Controller
{
private readonly IJobService _jobService;
public JobsController(IJobService jobService)
{
_jobService = jobService;
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create()
{
_jobService.CreateJob();
return RedirectToAction("Index");
}
}
Additional Reading : The Repository-Service pattern