I usually use AsNoTracking when I'm not intending to write anything. How should I handle this in my service layer where dbContext is hidden behind it? (I treat EF core as repository because it is repository)
public class SomeService
{
//...
public SomeEntity GetById(int id)
{
return _dbContext.Find(id);
}
public SomeEntity GetReadonlyById(int id)
{
return _dbContext.SomeEntitities.AsNoTracking().SingleOrDefault(e => e.Id == id);
}
public SomeEntity Update(SomeEntity someEntity)
{
_dbContext.Update(someEntity);
_dbContext.SaveChanges();
}
}
public class SomeController
{
private readonly SomeService _someService;
//....
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var someEntity = _someService.GetReadonlyById(id);
if (someEntity == null)
{
return NotFound();
}
return someEntity;
}
[HttpPut("{id}")]
public IActionResult Modify(int id, SomeEntity modified)
{
var someEntity = _someService.GetById(id);
if (someEntity == null)
{
return NotFound();
}
someEntity.Someproperty = modified.Someproperty;
_someService.Update(someEntity);
return Ok(someEntity);
}
}
Is there any better way to do this?
I can also define my service as follows:
public class SomeService
{
//...
public SomeEntity GetById(int id)
{
return _dbContext.AsNoTracking.SingleOrDefault(e => e.Id == id);
}
public SomeEntity Update(int id, SomeEntity someEntity)
{
var entity = _dbContext.SomeEntities.Find(id);
if (entity == null)
{
return null;
}
entity.Someproperty = someEntity.Someproperty;
_dbContext.Update(entity);
_dbContext.SaveChanges();
return entity;
}
}
public class SomeController
{
private readonly SomeService _someService;
//....
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var someEntity = _someService.GetById(id);
if (someEntity == null)
{
return NotFound();
}
return someEntity;
}
[HttpPut("{id}")]
public IActionResult Modify(int id, SomeEntity modified)
{
var someEntity = _someService.Update(id, modified);
if (someEntity == null)
{
return NotFound();
}
return Ok(someEntity);
}
}
What is the better way?
Basically, it is more common problem.
It is often happens that optimized reading methods are not convenient for updating scenarios and convenient reading methods for updating scenarios have unnecessary overhead for reading only scenarios. I see 3 options here:
GetById
from your first approach for reads and updates. Obviously, it is applicable for simple applications and may not be applicable for high-load applications.AsNoTracking
method or even use a plain sql
in repositories. It is applicable for complex apps and requires more code.As noted in comments your SomeService
looks like repository. Ideally, domain service should contain only business logic and shouldn't mix it with infrastructure features like AsNoTracking
. Whereas repositories can and should contain infrastructure features like AsNoTracking
, Include
and etc.