Меня интересует архитектурное решение следующего момента.
У меня есть:
public class GenericRepository<T> : IDisposable {
public GenericRepository(ISession session){
_session = session;
};
public T InsertAsync(T entity){...};
public IQueryable<T> Read(){...};
public T UpateAsync(T entity){...};
public void DeleteAsync(T entity){...};
public Task Commit(){
return _session.Transaction.Commit();
};
public void Dispose(){
if(_session.Transaction.IsActive){
_session.Transaction.Rollback();
}
};
}
public class UserService{
public UserService(GenericRepository<User> repository){...}
public long CreateUser(string userName){
...
_repository.Commit(); // [1]
};
}
public class OrganizationService{
public OrganizationService(GenericRepository<Organization> repository){...}
public int CreateOrganization(string code){
...
_repository.Commit(); // [2]
};
}
Используется следующая регистрация:
services.AddScoped<ISession>(x => x.GetRequiredService<NHSessionProvider>().OpenSession());
services.AddScoped(typeof(GenericRepository<>));
services.AddScoped<UserService>();
services.AddScoped<OrganizationService>();
Эти CreateOrganization
и CreateUser
могут использоваться независимо в любых частях кода:
public IActionResult Post([FromServices] OrganizationService service, [FromBody] string code){
service.CreateOrganization(code);
return Ok();
}
public IActionResult Post([FromServices] UserService service, [FromBody] string userName){
service.CreateUser(userName);
return Ok();
}
Однако теперь у меня есть новый сервис:
public class MyBillingService{
public MyBillingService(GenericRepository<Contractor> repository, OrganizationService organizationService, UserService userService){...}
public int CreateNewContractor(string organizationCode, string userName){
...
_organizationService.CreateOrganization(organizationCode);
...
_userService.CreateUser(userName);// [3]
...
_repository.Commit(); // [4]
}
}
В этой реализации CreateOrganization
и CreateUser
имеют свои собственные транзакции, и если [3] выдает исключение, то организация все равно будет создана.Хорошо, поскольку ISession
зарегистрирован как Scoped, тогда я могу удалить _repository.Commit
из CreateOrganization
и CreateUser
([1] и [2]).В этом случае [4] будет отвечать за принятие всех изменений.
Но что тогда делать, когда OrganizationService
и UserService
используются независимо?В конце концов, теперь они стали независимыми службами и не могут сохранять данные без делегирования изменений в какой-либо другой службе:
public IActionResult Post([FromServices] UserService service, [FromServices] TransactionService transaction, [FromBody] string userName){
service.CreateUser(userName);
transaction.Commit();
return Ok();
}
Насколько это решение является хорошим