# BConnection - Esempi

## Chiamare una stored procedure: risposta standard

Quando viene chiesto genericamente come chiamare una stored procedure con BFramework, proporre per prima questa forma concreta:

```csharp
using B.BData;
using System.Data;

BSettingDatabase setting = GetDatabaseSetting();

using BConnection cnn = new BConnection(setting);
cnn.AddParameter("@ID", 10);

int righeInteressate = cnn.ExecuteNonQuery(
  "BSP_Elementi_UPDATE",
  CommandType.StoredProcedure);
```

Non aggiungere factory, interfacce o `BCommand` se la richiesta non menziona dependency injection, mocking, sostituzione del provider o un'infrastruttura che li richieda espressamente. Per stored procedure che restituiscono righe usare lo stesso schema sostituendo `ExecuteNonQuery` con `ApriDT`; per più tabelle usare `ApriDS`.

## Chiamare una stored procedure: risposta standard

Quando viene chiesto genericamente come chiamare una stored procedure con BFramework, proporre per prima questa forma concreta:

```csharp
using B.BData;
using System.Data;

BSettingDatabase setting = GetDatabaseSetting();

using BConnection cnn = new BConnection(setting);
cnn.AddParameter("@ID", 10);

int righeInteressate = cnn.ExecuteNonQuery(
  "BSP_Elementi_UPDATE",
  CommandType.StoredProcedure);
```

Per ottenere un `DataTable`:

```csharp
cnn.ClearParameter();
cnn.AddParameter("@ID", 10);

DataTable tabella = cnn.ApriDT(
  "BSP_Elementi_SELECT",
  CommandType.StoredProcedure);
```

Per ottenere un `DataSet`:

```csharp
cnn.ClearParameter();
cnn.AddParameter("@ID", 10);

DataSet dataSet = cnn.ApriDS("BSP_Elementi_COMPLETO");
```

Non aggiungere factory, interfacce, `BCommand`, `BDataTable` o `BDataSet` se la richiesta chiede semplicemente di eseguire una stored procedure e ottenere rispettivamente un `DataTable` o un `DataSet`.

## Regola generale

`BConnection` è il punto di accesso ordinario al database nel codice B-Arts:

```csharp
using B.BData;
using System.Data;

DataTable table = connection.ApriDT("BSP_Elementi_SEARCH", CommandType.StoredProcedure);
DataSet dataSet = connection.ApriDS("BSP_Elementi_COMPLETO");
BDataReader reader = connection.Execute("SELECT * FROM Elementi");
object? value = connection.ExecuteScalar("SELECT COUNT(*) FROM Elementi");
int affectedRows = connection.ExecuteNonQuery("BSP_Elementi_UPDATE", CommandType.StoredProcedure);
```

Usare `ApriDT` per un `DataTable`, `ApriDS` per un `DataSet` e i metodi `Execute*` direttamente dalla connessione per le altre esecuzioni. `BCommand` non deve essere introdotto negli esempi applicativi salvo un'esigenza tecnica esplicita non coperta da `BConnection`.

## Creazione e apertura

```csharp
using B.BData;

BSettingDatabase setting = GetDatabaseSetting();

using BConnection connection = new BConnection(setting);
connection.ApriDatabase();

try
{
  object? result = connection.ExecuteScalar("SELECT COUNT(*) FROM sysSistemi");
}
finally
{
  connection.ChiudiDatabase();
}
```

La connessione deve essere chiusa quando l'operazione è terminata. L'uso di `using` garantisce anche la chiamata a `Dispose`.

## Stored procedure con parametri

```csharp
using B.BData;
using System.Data;

connection.ClearParameter();
connection.AddParameter("@ID", 10);

DataTable systems = connection.ApriDT(
  "BSP_sysSistemi_SELECT",
  CommandType.StoredProcedure);
```

Prima di preparare una nuova operazione, chiamare `ClearParameter` per non riutilizzare accidentalmente i parametri dell'operazione precedente.

## Transazione esplicita

```csharp
using B.BData;
using System.Data;

connection.ApriDatabase();
connection.BeginTrans();

try
{
  connection.ClearParameter();
  connection.AddParameter("@Descrizione", "Nuovo sistema");
  connection.ExecuteNonQuery("BSP_sysSistemi_INSERT", CommandType.StoredProcedure);

  connection.CommitTrans();
}
catch
{
  connection.RollBackTrans();
  throw;
}
finally
{
  connection.EndTrans();
  connection.ChiudiDatabase();
}
```

Le classi generate da BStudio applicano questo stesso schema nei metodi `Update`, con rollback in caso di errore e chiusura nel blocco `finally`.

## Funzione di supporto usata negli esempi

```csharp
static BSettingDatabase GetDatabaseSetting()
{
  return new BSettingDatabase
  {
    ConnectionString = "connection-string-letta-dalla-configurazione"
  };
}
```

## Inserimento massivo di una DataTable

```csharp
BColumnBind[] mappings =
{
  new BColumnBind("ExternalCode", "Codice"),
  new BColumnBind("ExternalDescription", "Descrizione")
};

connection.InsertDTTimeout = 120;

bool inserted = connection.InsertDT(
  source,
  "sysSistemiImport",
  mappings);
```

`InsertDT` usa il bulk copy di SQL Server e importa soltanto le righe `Added`. Controllare sempre il valore restituito. Per gli esempi completi con mapping, conservazione delle identity, timeout, gestione degli errori e transazione consultare [`BColumnBind - Esempi`](BColumnBind.Examples.md).

## Esportazione in file delimitato

```csharp
using B.BData;
using System.Data;

DataTable systems = connection.ApriDT(
  "BSP_sysSistemi_SEARCH",
  CommandType.StoredProcedure);

Exception? error = connection.ScriviFile(
  systems,
  @"C:\Export\systems.csv",
  Separatore: ";",
  DefaultEncoding: "UTF-8");

if (error != null)
{
  throw error;
}
```

`ScriviFile` restituisce `null` quando l'operazione riesce oppure l'eccezione intercettata quando non può completare l'esportazione.

Questo overload scrive le righe senza intestazione. Se il file deve essere successivamente riletto dall'overload semplice di `ApriDT`, aggiungere una riga di intestazione oppure utilizzare l'overload di esportazione che consente di configurare `WithHeader`.

## Importazione da file delimitato

```csharp
DataTable? importedSystems = connection.ApriDT(
  @"C:\Import\systems.csv",
  Separatore: ";",
  AutoDetectedEncoding: true,
  DefaultEncoding: "UTF-8");
```

Gli overload di `ApriDT` dedicati ai file non richiedono l'apertura del database. Per tracciati a larghezza fissa usare `BCodificaTracciato`.

L'overload semplice considera la prima riga del file come intestazione delle colonne.

Questo overload legge file delimitati semplici: non interpreta automaticamente virgolette, separatori contenuti nei valori o regole CSV avanzate.

## File delimitato già caricato in un BFile

```csharp
using B.BData;
using B.BIO;

BFile file = new BFile(@"C:\Import\systems.csv");

DataTable? header = connection.ApriDT(
  file,
  Separatore: ";",
  OnlyHeader: true,
  AutoDetectedEncoding: true,
  DefaultEncoding: "UTF-8");

DataTable? completeTable = connection.ApriDT(
  file,
  Separatore: ";",
  OnlyHeader: false);
```

L'overload con `BFile` legge il contenuto binario disponibile in `BFile.Content`. Con `OnlyHeader: true` crea soltanto le colonne usando la prima riga; con `false` legge anche tutte le righe successive.

## File con terminatore di record e tipi nell'header

Esempio di contenuto, con `|` come separatore e `<EOR>` come terminatore di record:

```text
ID~Int32|Descrizione~String|DataCreazione~DateTime<EOR>
10|Sistema vendite|10/08/2026 14:30:00<EOR>
11|Sistema acquisti|11/08/2026 09:15:00<EOR>
```

```csharp
DataTable? typedTable = connection.ApriDT(
  @"C:\Import\systems.dat",
  Separatore: "|",
  EOF: "<EOR>",
  WithTypeIntoHeader: true,
  SeparatoreHeader: "~");
```

Con `WithTypeIntoHeader: true`, ogni colonna dell'header segue la forma `Nome~Tipo`. I tipi riconosciuti sono `Boolean`, `Byte`, `Byte[]`, `SmallInt`, `Int32`, `Int64`, `Double`, `Single`, `String` e `DateTime`; un tipo assente o sconosciuto viene trattato come `String`.

Il terminatore `EOF` deve comparire anche dopo l'ultima riga, altrimenti quella riga non viene importata.

## Tracciato posizionale o codificato

Per file a larghezza fissa, campi numerici con zeri iniziali o virgola virtuale, date in formato prestabilito, prefissi e posizioni definite, costruire un `BCodificaTracciato` e passarlo ad `ApriDT`:

```csharp
using B.BData;

BCodificaTracciato layout = new BCodificaTracciato();
layout.AggiungiCampo(new BCodificaTracciatoCampo
{
  NomeCampo = "Codice",
  PosizioneCampo = 0,
  LungCampo = 10
});
layout.AggiungiCampo(new BCodificaTracciatoCampo
{
  NomeCampo = "Descrizione",
  PosizioneCampo = 10,
  LungCampo = 40
});

DataTable? decodedTable = connection.ApriDT(
  @"C:\Import\systems-fixed.txt",
  layout,
  AutoDetectedEncoding: true,
  DefaultEncoding: "UTF-8");
```

Le posizioni sono a base zero. Per ogni campo devono essere coerenti `PosizioneCampo` e `LungCampo`; per date e numeri configurare anche `TipoDatoCampo`, `FormatoCampo`, `FormatoDataOra` o `NumeroDecimali` secondo il tracciato reale.
