在我的 API 中,我使用测试。测试可以包含问题,问题可以包含答案和图像。
以最简单的方式更新项目我删除测试+问题+答案+图像,然后在同一交易中使用新值再次“放置”它们。
这样做我收到一个"Transaction request cannot include multiple operations on one item"
异常。
CreateTestAsync
:
public async Task<int> CreateTestAsync(TestDTO testDto, int saveMode)
{
if (testDto.Questions == null) return Result.KO;
try
{
//save test data
//var table = Table.LoadTable(_client, Tables.Tests.TableName);
transactionActions = new List<TransactWriteItem>();
//delete items first
if (saveMode == SaveMode.Update)
{
Delete delete;
Dictionary<string, AttributeValue> key;
if (testDto.Questions != null)
{
foreach (var question in testDto.Questions)
{
if (question.Answers != null)
{
foreach (var answer in question.Answers)
{
//delete answer
delete = DeleteElementAsync1(Tables.Answers.TableName, Tables.Answers.Fields.Id, answer.Id);
transactionActions.Add(new TransactWriteItem { Delete = delete });
}
}
if (question.Images != null)
{
foreach (var image in question.Images)
{
//delete image
delete = DeleteElementAsync1(Tables.Images.TableName, Tables.Images.Fields.Id, image.Id);
transactionActions.Add(new TransactWriteItem { Delete = delete });
//delete image from S3
}
}
//delete question
delete = DeleteElementAsync1(Tables.Questions.TableName, Tables.Questions.Fields.Id, question.Id);
transactionActions.Add(new TransactWriteItem { Delete = delete });
}
}
//delete test
delete = DeleteElementAsync1(Tables.Tests.TableName, Tables.Tests.Fields.Id, testDto.Id);
transactionActions.Add(new TransactWriteItem { Delete = delete });
}
//save test
var json = JsonConvert.SerializeObject(testDto);
var document = Document.FromJson(json);
document.Remove("Questions");
var testTable = Table.LoadTable(_client, Tables.Tests.TableName);
var put = GeneratePutAsync(document, testTable, Tables.Tests.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
//save items then
if (testDto.Questions != null && testDto.Questions.Any())
{
//save questions
var questionsTable = Table.LoadTable(_client, Tables.Questions.TableName);
foreach (var question in testDto.Questions)
{
json = JsonConvert.SerializeObject(question);
document = Document.FromJson(json);
document.Remove("Answers");
document.Remove("Images");
put = GeneratePutAsync(document, questionsTable, Tables.Questions.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
if (question.Answers != null && question.Answers.Any())
{
var answersTable = Table.LoadTable(_client, Tables.Answers.TableName);
foreach (var answer in question.Answers)
{
json = JsonConvert.SerializeObject(answer);
document = Document.FromJson(json);
put = GeneratePutAsync(document, answersTable, Tables.Answers.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
}
}
if (question.Images != null && question.Images.Any())
{
var imagesTable = Table.LoadTable(_client, Tables.Images.TableName);
foreach (var image in question.Images)
{
json = JsonConvert.SerializeObject(image);
document = Document.FromJson(json);
put = GeneratePutAsync(document, imagesTable, Tables.Images.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
}
}
}
}
var transactionResult = await RunTransaction(transactionActions);
return Result.OK;
}
catch (Exception e)
{
return Result.KO;
}
}
RunTransactions
:
private async Task<int> RunTransaction(List<TransactWriteItem> actions)
{
var transaction = new TransactWriteItemsRequest()
{
TransactItems = actions,
ReturnConsumedCapacity = ReturnConsumedCapacity.TOTAL
};
// Run the transaction and process the result.
try
{
var transactionResult = await _client.TransactWriteItemsAsync(transaction);
Console.WriteLine("Transaction Successful");
return Result.OK;
}
catch (ResourceNotFoundException rnf)
{
Console.Error.WriteLine("One of the table involved in the transaction is not found" + rnf.Message);
return Result.KO;
}
catch (InternalServerErrorException ise)
{
Console.Error.WriteLine("Internal Server Error" + ise.Message);
return Result.KO;
}
catch (TransactionCanceledException tce)
{
Console.Error.WriteLine("Transaction Canceled " + tce.Message);
return Result.KO;
}
catch (Exception tce)
{
Console.Error.WriteLine("General error: " + tce.Message);
return Result.KO;
}
}
确实,我在同一个元素中包含了多个操作(在我的例子中为“Delete + Put”),但我必须这样做。此外,它们是不同的操作。
我检查了这个交易请求不能包含对一个项目python的多个操作,但它不包含解决方案。
我知道最好是进行更新而不是删除+插入,问题是如果我要更新或插入,我需要检查每个问题、答案和图像,这可能会使我的代码更加复杂。有什么解决办法吗?
工作解决方案:
public async Task<int> CreateTestAsync(TestDTO testDto)
{
if (testDto.Questions == null) return Result.KO;
try
{
//save test data
transactionActions = new List<TransactWriteItem>();
//save test
var json = JsonConvert.SerializeObject(testDto);
var document = Document.FromJson(json);
document.Remove("Questions");
var testTable = Table.LoadTable(_client, Tables.Tests.TableName);
var put = GeneratePutAsync(document, testTable, Tables.Tests.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
//save items then
if (testDto.Questions != null && testDto.Questions.Any())
{
//save questions
var questionsTable = Table.LoadTable(_client, Tables.Questions.TableName);
foreach (var question in testDto.Questions)
{
json = JsonConvert.SerializeObject(question);
document = Document.FromJson(json);
document.Remove("Answers");
document.Remove("Images");
put = GeneratePutAsync(document, questionsTable, Tables.Questions.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
if (question.Answers != null && question.Answers.Any())
{
var answersTable = Table.LoadTable(_client, Tables.Answers.TableName);
foreach (var answer in question.Answers)
{
json = JsonConvert.SerializeObject(answer);
document = Document.FromJson(json);
put = GeneratePutAsync(document, answersTable, Tables.Answers.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
}
}
if (question.Images != null && question.Images.Any())
{
var imagesTable = Table.LoadTable(_client, Tables.Images.TableName);
foreach (var image in question.Images)
{
json = JsonConvert.SerializeObject(image);
document = Document.FromJson(json);
put = GeneratePutAsync(document, imagesTable, Tables.Images.Fields.Id);
transactionActions.Add(new TransactWriteItem { Put = put });
}
}
}
}
var transactionResult = await RunTransaction(transactionActions);
return Result.OK;
}
catch (Exception e)
{
return Result.KO;
}
}
“RunTransaction”方法保持完整,如原始问题中所示。