SQL Server · UpdateMultiple
Put accounts on hold (selection set, by key)
Credit control puts accounts on hold, in three scenarios: one account by its account number (the declared key); a value the status picklist doesn't allow is refused before the database; every account of a segment at once.
Set up for this page
The scenarios build on the sample application: SampleContext.cs (the dbContext every sample is given); SampleOutput.cs (Step and Show, which print); SampleContext.Application.cs (dbContext.Service, the application's ARX service); SampleCatalog.cs (the tables' ids, keys, lookups and display names).
Before scenario 1 the sample runs this, so the service and the rows the scenarios use are there:
foreach (var (number, segment) in new[] { ("ACC-U701", "smb"), ("ACC-U702", "smb"), ("ACC-U703", "smb") })
{
var account = new ArxEntity("account");
account["name"] = "On hold customer " + number;
account["account_number"] = number;
account["segments"] = segment;
await service.CreateAsync(account);
}1 One account, by its account number
The credit team knows the account number, not the id: find the row by the declared key.
Already in scope: service (ArxMsSqlDbService)
var hold = new ArxEntity("account");
hold["account_number"] = "ACC-U701";
hold["status"] = new ArxSelectionSetValue("AccountStatus", "ON_HOLD");
await service.UpdateAsync(hold, new ArxUpdateOptions { Match = ArxMatch.Key("account_number"), RequireSingleRow = true });
Console.WriteLine("ACC-U701 is ON_HOLD");Check it in the database
Run it in any SQL tool connected to the database, after the code has run.
SELECT account_number, status
FROM account
WHERE account_number = 'ACC-U701';Expect: 1 row, ON_HOLD.
2 A value the picklist doesn't allow
"SUSPENDED" isn't an AccountStatus option: refused by the catalog, nothing sent.
Already in scope: service (ArxMsSqlDbService)
var hold = new ArxEntity("account");
hold["account_number"] = "ACC-U702";
hold["status"] = new ArxSelectionSetValue("AccountStatus", "SUSPENDED");
try
{
await service.UpdateAsync(hold, new ArxUpdateOptions { Match = ArxMatch.Key("account_number") });
}
catch (ArxValidationException error)
{
Console.WriteLine(error.Message);
}Check it in the database
Run it in any SQL tool connected to the database, after the code has run.
SELECT account_number, status
FROM account
WHERE account_number = 'ACC-U702';Expect: 1 row, ACTIVE (the default): unchanged.
3 Several accounts in one call
Several accounts by their numbers in one call: each found by its key, all or nothing.
Already in scope: service (ArxMsSqlDbService)
var holds = new[] { "ACC-U701", "ACC-U703" }.Select(number =>
{
var hold = new ArxEntity("account");
hold["account_number"] = number;
hold["status"] = new ArxSelectionSetValue("AccountStatus", "ON_HOLD");
return hold;
}).ToList();
var changed = await service.UpdateMultipleAsync(holds, new ArxUpdateOptions { Match = ArxMatch.Key("account_number") });
Console.WriteLine($"{changed} accounts on hold");Check it in the database
Run it in any SQL tool connected to the database, after the code has run.
SELECT account_number, status
FROM account
WHERE account_number IN ('ACC-U701', 'ACC-U702', 'ACC-U703')
ORDER BY account_number;Expect: ACC-U701 ON_HOLD, ACC-U702 ACTIVE (refused in scenario 2), ACC-U703 ON_HOLD.
Run the complete sample
The code above comes from one program, built in a fresh project and run against the database. To run it yourself, here is every file and step.
The program, its files and how to run it
Run it locally
- .NET SDK: .NET SDK 10.0.100 or later 10.0.x (target
net10.0). - Create the project:
Terminal dotnet new console -n ArxSample -f net10.0 cd ArxSample - Install the packages:
Terminal dotnet add package ARX.SDK.SQL --version 1.0.0-rc.1 - Database: a SQL Server 2022 (tested with 16.0.4225.2) database with the sample schema.
- Configuration: set
ARX_SAMPLES_SQLSERVERto its connection string. Nothing is hard-coded. - Source code: add the files of the sample application this sample uses (
SampleContext.cs,SampleOutput.cs,SampleContext.Application.cs,SampleCatalog.cs), then replaceProgram.csand add the other file below, with the file names shown. - Run it:
Terminal dotnet run - Expected output: below.
The files
Runs the sample. Generated for this page; it reads the connection string from the environment.
using ArxSamples.MSSQL;
using ArxSamples.MSSQL.Operations.UpdateMultiple.RealCases;
// The connection string comes from the environment, never from the code (see "Configure the connection").
var connectionString = Environment.GetEnvironmentVariable("ARX_SAMPLES_SQLSERVER")
?? throw new InvalidOperationException("Set the ARX_SAMPLES_SQLSERVER environment variable to your SQL Server connection string.");
await new RealCase1_PutAnAccountOnHold().RunAsync(new SampleContext(connectionString));
The sample, as it is in the repository.
using ARX.SDK;
using ARX.SDK.Services;
using static ArxSamples.MSSQL.SampleOutput;
namespace ArxSamples.MSSQL.Operations.UpdateMultiple.RealCases;
/// <summary>
/// Credit control puts accounts on hold, in three scenarios: one account by its account number (the declared key); a
/// value the status picklist doesn't allow is refused before the database; every account of a segment at once.
/// </summary>
public sealed class RealCase1_PutAnAccountOnHold : ISample
{
public string Name => "update-multiple-real-1-put-an-account-on-hold";
public string Title => "Put accounts on hold (selection set, by key)";
public async Task RunAsync(SampleContext dbContext)
{
foreach (var (number, segment) in new[] { ("ACC-U701", "smb"), ("ACC-U702", "smb"), ("ACC-U703", "smb") })
{
var account = new ArxEntity("account");
account["name"] = "On hold customer " + number;
account["account_number"] = number;
account["segments"] = segment;
await dbContext.Service.CreateAsync(account);
}
await Scenario1_OneAccountByItsNumberAsync(dbContext);
await Scenario2_AValueThePicklistDoesntAllowAsync(dbContext);
await Scenario3_ManyAccountsAtOnceAsync(dbContext);
}
/// <summary>1. The credit team knows the account number, not the id: find the row by the declared key.</summary>
private static async Task Scenario1_OneAccountByItsNumberAsync(SampleContext dbContext)
{
Step("1. One account, by its account number");
var hold = new ArxEntity("account");
hold["account_number"] = "ACC-U701";
hold["status"] = new ArxSelectionSetValue("AccountStatus", "ON_HOLD");
await dbContext.Service.UpdateAsync(hold, new ArxUpdateOptions { Match = ArxMatch.Key("account_number"), RequireSingleRow = true });
Show("ACC-U701 is ON_HOLD");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT account_number, status
* FROM account
* WHERE account_number = 'ACC-U701';
* -- Expect: 1 row, ON_HOLD.
* ===========================================================
*/
}
/// <summary>2. "SUSPENDED" isn't an AccountStatus option: refused by the catalog, nothing sent.</summary>
private static async Task Scenario2_AValueThePicklistDoesntAllowAsync(SampleContext dbContext)
{
Step("2. A value the picklist doesn't allow");
var hold = new ArxEntity("account");
hold["account_number"] = "ACC-U702";
hold["status"] = new ArxSelectionSetValue("AccountStatus", "SUSPENDED");
try
{
await dbContext.Service.UpdateAsync(hold, new ArxUpdateOptions { Match = ArxMatch.Key("account_number") });
}
catch (ArxValidationException error)
{
ShowError(error);
}
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT account_number, status
* FROM account
* WHERE account_number = 'ACC-U702';
* -- Expect: 1 row, ACTIVE (the default): unchanged.
* ===========================================================
*/
}
/// <summary>3. Several accounts by their numbers in one call: each found by its key, all or nothing.</summary>
private static async Task Scenario3_ManyAccountsAtOnceAsync(SampleContext dbContext)
{
Step("3. Several accounts in one call");
var holds = new[] { "ACC-U701", "ACC-U703" }.Select(number =>
{
var hold = new ArxEntity("account");
hold["account_number"] = number;
hold["status"] = new ArxSelectionSetValue("AccountStatus", "ON_HOLD");
return hold;
}).ToList();
var changed = await dbContext.Service.UpdateMultipleAsync(holds, new ArxUpdateOptions { Match = ArxMatch.Key("account_number") });
Show($"{changed} accounts on hold");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT account_number, status
* FROM account
* WHERE account_number IN ('ACC-U701', 'ACC-U702', 'ACC-U703')
* ORDER BY account_number;
* -- Expect: ACC-U701 ON_HOLD, ACC-U702 ACTIVE (refused in scenario 2), ACC-U703 ON_HOLD.
* ===========================================================
*/
}
}
Expected output
What dotnet run printed when the sample was verified, on a freshly created sample schema. Ids differ when the tables already hold rows.
> 1. One account, by its account number
ACC-U701 is ON_HOLD
> 2. A value the picklist doesn't allow
caught ArxValidationException: ARX1011 SelectionSetValueNotAllowed: Selection set 'AccountStatus' has no option with this code (or the code is of another kind) (attribute 'status' on 'account').
> 3. Several accounts in one call
2 accounts on hold