I am trying to update the table. But it does not. How come, I don't understand. There is no error either.
...
var gameBankResult =
await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
g.productCode == requestDto.productCode && g.referenceId == Guid.Empty); --> returns 1 result
//If we have exact number of games in our database, mark them!
if (gameBankResult.Count() != 0 && gameBankResult.Count() >= requestDto.quantity)
{
for (var index = 0; index < requestDto.quantity; index++)
{
var item = gameBankResult[index];
item.referenceId = gameRequest.referenceId;
item.requestDateTime = DateTime.Now;
item.responseDateTime = DateTime.Now;
_unitOfWork.GameBankRepository.Update(item);await _unitOfWork.SaveAsync(); ---> does not update the table
}
//Query GameBank database
var gameBankConfirmResult =
await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
g.referenceId == gameRequest.referenceId); ---> returns no result
...
It is due to Transaction scope. If I don't use Transaction scope it is updated immediately but this time how can I rollback if one of the insert/updates fails.
private async Task<HttpResponseMessage> CallGame(RequestDto requestDto)
{
HttpResponseMessage response = null;
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
//Transform DTO into GameRequest for calling Game Initiate
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<RequestDto, GameRequest>();
cfg.CreateMap<GameRequest, GameConfirmRequest>();
cfg.CreateMap<GameBank, GameConfirmResponse>();
cfg.CreateMap<GameBankPin, Coupon>();
cfg.CreateMap<GameRequest, GameRequestDto>();
});
var iMapper = config.CreateMapper();
var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
//Unique reference ID
gameRequest.referenceId = Guid.NewGuid();
var gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);
//Create signature
gameRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Initiate);
//Add initiation request into database
_unitOfWork.GameRepository.Insert(gameRequest);
//Query GameBank database
var gameBankResult =
await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
g.productCode == requestDto.productCode && g.referenceId == Guid.Empty);
//If we have exact number of games in our database, mark them!
if (gameBankResult.Count() != 0 && gameBankResult.Count() >= requestDto.quantity)
{
for (var index = 0; index < requestDto.quantity; index++)
{
var item = gameBankResult[index];
item.referenceId = gameRequest.referenceId;
item.requestDateTime = DateTime.Now;
item.responseDateTime = DateTime.Now;
_unitOfWork.GameBankRepository.Update(item);
await _unitOfWork.SaveAsync();
}
//Query GameBank database
var gameBankConfirmResult =
await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
g.referenceId == gameRequest.referenceId);
if (gameBankConfirmResult != null)
{
if (gameBankConfirmResult.Count == 1)
{
var gameBankConfirmResponse = iMapper.Map<IList<GameBank>, IList<GameConfirmResponse>>(gameBankConfirmResult);
gameBankConfirmResponse[0].purchaseStatusDate = DateTime.Now;
//Add confirm response into database
_unitOfWork.GameConfirmResponseRepository.Insert(gameBankConfirmResponse[0]);
var resultResponse = JsonConvert.SerializeObject(
gameBankConfirmResponse[0],Formatting.Indented,
new JsonSerializerSettings()
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
response = new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(
resultResponse, System.Text.Encoding.UTF8,
"application/json"),
};
}
else if(gameBankConfirmResult.Count > 1)
{
var gameResult = new GameConfirmResponse
{
coupons = new List<Coupon>()
};
var price = 0.0;
var quantity = 0;
foreach (var item in gameBankConfirmResult)
{
price = price + item.unitPrice;
quantity = quantity + 1;
foreach (var coupons in item.coupons)
{
var gameCouponResult = new Coupon()
{
expiryDate = coupons.expiryDate,
Pin = coupons.Pin,
Serial = coupons.Serial
};
//Add coupon values
gameResult.coupons.Add(gameCouponResult);
}
}
//Set summed/counted values
gameResult.referenceId = gameBankConfirmResult[0].referenceId;
gameResult.productCode = gameBankConfirmResult[0].productCode;
gameResult.quantity = quantity;
gameResult.currency = gameBankConfirmResult[0].currency;
gameResult.unitPrice = gameBankConfirmResult[0].unitPrice;
gameResult.totalPrice = price;
gameResult.productDescription = gameBankConfirmResult[0].productDescription;
gameResult.totalPayablePrice = price;
//var gameBankConfirmResponse = iMapper.Map<GameBank, GameConfirmResponse>(gameResult);
//Add confirm response into database
_unitOfWork.GameConfirmResponseRepository.Insert(gameResult);
var resultResponse = JsonConvert.SerializeObject(
gameResult, Formatting.Indented,
new JsonSerializerSettings()
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
response = new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(
resultResponse, System.Text.Encoding.UTF8,
"application/json"),
};
}
}
}
await _unitOfWork.SaveAsync();
scope.Complete();
}
return response;
}
Keep your friends close and your enemies even closer
It seems you added your own transaction scope which may "hide" an actual problem you had previously. Instead I would drop using TransactionScope and would fix the actual issue.
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
context.SaveChanges();
ie do all changes to the "repository" and then call SaveChanges once.
When SaveChanges is called, EF inspect all objects attached to the context (directly or even indirectly ie an Order related to OrderDetails for example), and figure out how to update all that in the correct order
within a single transaction.
Add for example a 3rd row that would exceed the allowed length for this blog entry or maybe a value that already exists if you have a unique constraint and you'll see that if SaveChanges fails nothing at all is added to the db.
Similarly in the previous code you are calling SaveChanges from within a loop. In most cases you should do all changes and then call this one time at the end to save all changes (or no change at all).
Member
527 Points
2729 Posts
Update problem
Jul 24, 2019 06:52 PM|cenk1536|LINK
Hi,
I am trying to update the table. But it does not. How come, I don't understand. There is no error either.
Generic Repo:
Unit of work:
All-Star
18815 Points
3831 Posts
Re: Update problem
Jul 25, 2019 02:05 AM|Nan Yu|LINK
Hi cenk1536,
Please provide the entire codes . for example ,Unit of Work Class to help reproduce .
You can also refer to below code sample for Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application :
https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Best Regards,
Nan Yu
Member
527 Points
2729 Posts
Re: Update problem
Jul 25, 2019 05:37 AM|cenk1536|LINK
It is due to Transaction scope. If I don't use Transaction scope it is updated immediately but this time how can I rollback if one of the insert/updates fails.
All-Star
48570 Points
18082 Posts
Re: Update problem
Jul 25, 2019 11:44 AM|PatriceSc|LINK
As I tried to tell earlier this is already what EF 6 and EF Core does out of the box for SaveAsync: https://docs.microsoft.com/en-us/ef/core/saving/transactions
It seems you added your own transaction scope which may "hide" an actual problem you had previously. Instead I would drop using TransactionScope and would fix the actual issue.
Member
527 Points
2729 Posts
Re: Update problem
Jul 25, 2019 12:01 PM|cenk1536|LINK
How can I use BeginTransaction with unit of work? Any sample you can show?
All-Star
48570 Points
18082 Posts
Re: Update problem
Jul 25, 2019 12:34 PM|PatriceSc|LINK
It should be just;
ie do all changes to the "repository" and then call SaveChanges once.
When SaveChanges is called, EF inspect all objects attached to the context (directly or even indirectly ie an Order related to OrderDetails for example), and figure out how to update all that in the correct order within a single transaction.
Add for example a 3rd row that would exceed the allowed length for this blog entry or maybe a value that already exists if you have a unique constraint and you'll see that if SaveChanges fails nothing at all is added to the db.
Similarly in the previous code you are calling SaveChanges from within a loop. In most cases you should do all changes and then call this one time at the end to save all changes (or no change at all).
All-Star
58254 Points
15678 Posts
Re: Update problem
Jul 25, 2019 05:10 PM|bruce (sqlwork.com)|LINK
just rollback in the error handler:
but as suggested if you use an implicit transaction, it will be faster, as its done in a single batch, rather than as separate batches.
Member
527 Points
2729 Posts
Re: Update problem
Jul 28, 2019 06:16 PM|cenk1536|LINK
I keep the transaction but changed my business logic. Now everything works just I want.