У меня есть asyn c веб-API, который имеет службы и подключение к БД с использованием контекста EF. В одном из сервисов, где я внедряю контекст, используя DI, я хочу создать простой транзакционный сервис, такой как:
public async Task<int> ServiceMethod()
{
using (var transaction = context.Database.BeginTransaction())
{
await context.Table1.AddAsync(new Table1());
await context.SaveChangeAsync();
CallOtherservice(context);
await context.SaveChangeAsync();
transaction.Commit();
}
}
CallOtherService(Context context)
{
await context.Table2.AddAsync();
}
. Я теперь сменил CallOtherService (), чтобы вызвать исключение, и я ничего не ожидаю commit, но похоже, что изменения в Table1 сохраняются, несмотря на то, что транзакция должна их остановить. Я попытался вызвать Rollback () в инструкции try catch и использовать вместо нее TransactionScope (), но оба они были бесполезны. Кроме того, я заметил, что после вызова .BeginTransaction () context.Database.CurrentTransaction имеет значение null, что я считаю немного странным.
EDIT: метод, который я тестирую:
public async Task<int> AddMatchAsync(Models.Database.Match match)
{
//If match is null, nothing can be done
if (match == null)
return 0;
else
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
try
{
//If the match already exists, return its id
var dbId = await ExistsMatchAsync(match.HomeTeam.Name, match.AwayTeam.Name, match.Time);
if (dbId > 0)
{
log.Info($"Found match with id {dbId}");
return dbId;
}
//add computable data
match = await AttachMatchName(match);
match.Season = CommonServices.toSeason(match);
// Prepare the relational entities accordingly
match = PrepareTeamsForAddMatch(match).Result;
match = PrepareLeagueForAddMatch(match).Result;
//add the match and save it to the DB
await context.Matches.AddAsync(match);
await context.SaveChangesAsync();
log.Info($"Successfully added a new match! id: {match.Id}");
// Create new TeamLeagues entities if needed
leaguesService.CreateTeamLeaguesForNewMatchAsync(context, match);
await context.SaveChangesAsync();
scope.Complete();
return match.Id;
}
catch (Exception ex)
{
log.Error($"Error adding match - Rolling back: {ex}");
throw;
}
}
}
}
и тест:
[Test]
public void AddMatchSaveChangesTransaction()
{
//Arrange
var exceptiontext = "This exception should prevent the match from being saved";
var leagueServiceMock = new Mock<ILeaguesService>();
leagueServiceMock.Setup(p => p.CreateTeamLeaguesForNewMatchAsync(It.IsAny<InFormCoreContext>(),It.IsAny<Match>()))
.Throws(new Exception(exceptiontext));
leagueServiceMock.Setup(p => p.GetLeagueAsync(It.IsAny<string>()))
.ReturnsAsync((string name) => new League{Id = 1, Name = name });
var match = new Match
{
HomeTeam = new Team { Name = "Liverpool" },
AwayTeam = new Team { Name = "Everton" },
League = new League { Name = "PL", IsSummer = true },
Time = DateTime.UtcNow,
HomeGoals = 3,
AwayGoals = 0
};
var mcount = context.Matches.Count();
//Act
var matchService = new MatchesService(context, leagueServiceMock.Object, new LogNLog(), TeamsService);
//Assert
var ex = Assert.ThrowsAsync<Exception>(async () => await matchService.AddMatchAsync(match));
Assert.AreEqual(ex.Message, exceptiontext);
Assert.AreEqual(mcount, context.Matches.Count(), "The match has been added - the transaction does not work");
}`
```