MySQL · 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:

Set up
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 (ArxMySqlDbService)

C#
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

SQL

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 (ArxMySqlDbService)

C#
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

SQL

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 (ArxMySqlDbService)

C#
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

SQL

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

  1. .NET SDK: .NET SDK 10.0.100 or later 10.0.x (target net10.0).
  2. Create the project:
    Terminal
    dotnet new console -n ArxSample -f net10.0
    cd ArxSample
  3. Install the packages:
    Terminal
    dotnet add package ARX.SDK.MySQL --version 1.0.0-rc.1
  4. Database: a MySQL 8.4 (tested with 8.4.13) database with the sample schema.
  5. Configuration: set ARX_SAMPLES_MYSQL to its connection string. Nothing is hard-coded.
  6. Source code: add the files of the sample application this sample uses (SampleContext.cs, SampleOutput.cs, SampleContext.Application.cs, SampleCatalog.cs), then replace Program.cs and add the other file below, with the file names shown.
  7. Run it:
    Terminal
    dotnet run
  8. Expected output: below.

The files

Program.cs

Runs the sample. Generated for this page; it reads the connection string from the environment.

using ArxSamples.MySQL;
using ArxSamples.MySQL.Operations.UpdateMultiple.RealCases;

// The connection string comes from the environment, never from the code (see "Configure the connection").
var connectionString = Environment.GetEnvironmentVariable("ARX_SAMPLES_MYSQL")
    ?? throw new InvalidOperationException("Set the ARX_SAMPLES_MYSQL environment variable to your MySQL connection string.");

await new RealCase1_PutAnAccountOnHold().RunAsync(new SampleContext(connectionString));
RealCase1_PutAnAccountOnHold.cs

The sample, as it is in the repository.

using ARX.SDK;
using ARX.SDK.Services;
using static ArxSamples.MySQL.SampleOutput;

namespace ArxSamples.MySQL.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.

Output
  > 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