How to properly update multiple records in asp.net core 3.1?

0

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!

c#
asp.net-core
asp.net-web-api
entity-framework-core
azure-sql-data-warehouse
asked on Stack Overflow Jun 30, 2020 by Riad • edited Jul 1, 2020 by Panagiotis Kanavos

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0