I have an API (PUT) request like the following:
{{APIBaseUrl}}/accounts/mappingType
The request body looks like the following:
[
{
"CompanyId" : "AA",
"AccountIndex": 134,
"Value": "TTTTTTT"
},
{
"CompanyId" : "A",
"AccountIndex": 5148,
"Value": "TTTTTTT"
},
{
"CompanyId" : "B",
"AccountIndex": 5146,
"Value": "TTTTTTT"
}
]
The mappingType
in the http request will be translated into a column name where the update is happening (it is not the actual column name, it is just an indicator).
The primary key for the record that I want to update its mappingType
column with the Value
is determined by the CompanyId
and AccountIndex
in the body request (composite PK).
Ex: Update mappingType from MY_TABLE WHERE company_id = CompanyId and account_index = AccountIndex
I am applying the repository pattern and I am trying to perform all the necessary updates..
My Controller looks like this:
[HttpPut("{mappingType}")]
public async Task<ActionResult<AccountForUpdateDto>> UpdateAccountMapping(string mappingType, [FromBody]AccountForUpdateDto[] accountsForUpdate)
{
foreach (var account in accountsForUpdate)
{
GpAccounts gpAccount = await _repo.GetGpAccountsByAccountIndexAndCompanyId(account.CompanyId, account.AccountIndex);
if (gpAccount == null) {
return NotFound("Could not find account!");
}
if (mappingType == "m1") {
gpAccount.Mapping1= account.Value;
} else if (mappingType == "m2") {
gpAccount.Mapping2= account.Value;
} else if (mappingType == "m3") {
gpAccount.Mapping3= account.Value;
} else {
return BadRequest("Mapping Not Allowed");
}
}
if (await _repo.SaveChangesAsync())
return NoContent();
return BadRequest();
}
My Repo code looks like this:
public async Task<GpAccounts> GetGpAccountsByAccountIndexAndCompanyId(string cid, int ain)
{
IQueryable<GpAccounts> query = _context.GpAccounts.Where(x => x.AccountIndex == ain && x.CompanyId == cid);
return await query.FirstOrDefaultAsync();
}
public async Task<bool> SaveChangesAsync() {
// Only return success if at least one row was changed
return (await _context.SaveChangesAsync()) > 0;
}
and finally the GpAccounts Model (db model) looks like this
public partial class GpAccounts
{
public string CompanyId { get; set; }
public int AccountIndex { get; set; }
public string Mapping1{ get; set; }
public string Mapping2 { get; set; }
public string Mapping3 { get; set; }
}
As you can see, mappingType
could be translated into Mapping1/Mapping2/Mapping3 which is the column that I am trying to update its value with the Value
coming from the request body.
Is there a better way to do this update, how? as you can see I am looping through all the accounts and creating/executing one single insert at a time.
UPDATED I made some changes on the code and now I am getting this exception when I call the api
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Must declare the scalar variable "@@ROWCOUNT".
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__164_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__274_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:703a99c6-39e0-4d4b-ab25-15f5124aa8e1
Error Number:137,State:1,Class:16
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at GPAccounts.API.Data.Repository.Repo.SaveChangesAsync() in C:\Users\rjaradeh.{{path}}\Repo.cs:line 31
at GPAccounts.API.Controllers.AccountsController.UpdateAccountMapping(String mappingType, AccountForUpdateDto[] accountsForUpdate) in {{path}}\AccountsController.cs:line 68
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I am using Azure SQL Data Warehouse!
User contributions licensed under CC BY-SA 3.0