# BConnection

## Identità

- Namespace: `B.BData`
- Assembly: `BFramework`
- Tipo: class
- Interfacce: `IDisposable`, `IBConnection`
- Sorgente API: versione `5.0.0`

## Scopo

`BConnection` è il punto di accesso standard al database nel normale codice applicativo B-Arts. Si istanzia direttamente, riceve i parametri tramite `AddParameter` ed esegue query o stored procedure con `ApriDT`, `ApriDS` e i metodi `Execute*`.

Non introdurre `IBConnection`, `IBConnectionFactory`, `BConnectionFactory`, `BCommand` o `BDataSet` per una normale chiamata al database. Factory e interfacce sono appropriate soltanto quando il progetto richiede esplicitamente dependency injection, sostituzione dell'implementazione o infrastruttura di servizio. `BDataSet` rimane utile quando serve specificamente quel tipo, ma non è il percorso ordinario per eseguire una stored procedure.

### Forma standard per una stored procedure senza risultato tabellare

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

using BConnection cnn = new BConnection(setting);
cnn.AddParameter("@parametro", valore);

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

`ExecuteNonQuery` verifica autonomamente lo stato della connessione, la apre quando necessario e la richiude se è stato il metodo ad aprirla. Una chiamata isolata non richiede quindi `ApriDatabase` e `ChiudiDatabase` espliciti.

## Uso applicativo standard

`BConnection` è il punto di accesso ordinario al database nel codice applicativo B-Arts. Si istanzia direttamente, riceve i parametri tramite `AddParameter` ed esegue query o stored procedure con `ApriDT`, `ApriDS` e i metodi `Execute*`.

Non introdurre `IBConnection`, `IBConnectionFactory`, `BConnectionFactory`, `BCommand` o `BDataSet` per una normale chiamata al database. Factory e interfacce sono appropriate soltanto quando il progetto richiede esplicitamente dependency injection, sostituzione dell'implementazione o un'infrastruttura di servizio. `BDataSet` va usato quando serve specificamente quel tipo, non come percorso ordinario per eseguire una stored procedure.

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

using BConnection cnn = new BConnection(setting);
cnn.AddParameter("@parametro", valore);

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

Per una stored procedure che restituisce una tabella:

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

Per una stored procedure che restituisce più tabelle:

```csharp
DataSet dataSet = cnn.ApriDS("NomeStoredProcedure");
```

`ApriDS` interpreta il nome ricevuto come stored procedure. Non creare un `BDataSet` quando è richiesto semplicemente un `DataSet`.

`ExecuteNonQuery` verifica lo stato della connessione, la apre quando necessario e la richiude se è stato il metodo ad aprirla. Una chiamata isolata non richiede `ApriDatabase` e `ChiudiDatabase` espliciti.

## Dichiarazione

```csharp
public class BConnection : IDisposable, IBConnection
```

## Costruttori

- `BConnection()`
- `BConnection(BSettingDatabase objSet)`
- `BConnection(string NomeServer, string NomeDB, string Utente, string Password)`

## Proprietà

| Proprietà | Tipo | Accesso |
|---|---|---|
| `Connection` | `IDbConnection` | `get` |
| `ConnectionTimeout` | `int` | `get/set` |
| `DefaultEncoding` | `Encoding` | `get/set` |
| `ExceptionList` | `List<Exception>` | `get/set` |
| `InsertDTTimeout` | `int` | `get/set` |
| `Parameters` | `BCollection` | `get/set` |
| `Setting` | `BSettingDatabase` | `get/set` |
| `Stato` | `ConnectionState` | `get` |
| `Transaction` | `IDbTransaction?` | `get` |

## Metodi

- `bool AddParameter(IDbDataParameter Param)`
- `void AddParameter(IDbDataParameter[] Params)`
- `bool AddParameter(string ParamName, object? ParamValue)`
- `void ApriDatabase()`
- `DataSet ApriDS(string SPName, int CommandTimeout = 30)`
- `DataSet ApriDS(string SPName, IDbDataParameter[] Params)`
- `DataTable ApriDT(string SqlCommand, IDbDataParameter[] Params)`
- `DataTable ApriDT(string SqlCommand, int CommandTimeout = 30, bool ExecuteFillSchema = true)`
- `DataTable ApriDT(string SqlCommand, int CommandTimeout, IDbDataParameter[] Params)`
- `DataTable ApriDT(string SqlCommand, CommandType TipoComando, int CommandTimeout = 30, bool ExecuteFillSchema = true)`
- `DataTable ApriDT(string SqlCommand, bool vReadOnly, int CommandTimeout = 30, bool ExecuteFillSchema = true)`
- `DataTable ApriDT(bool vReadOnly, string SqlCommand, bool ExecuteFillSchema = false, int CommandTimeout = 30)`
- `DataTable? ApriDT(string PathFile, string Separatore, bool AutoDetectedEncoding = true, string DefaultEncoding = "UTF-8")`
- `DataTable? ApriDT(string PathFile, BCodificaTracciato Codifica, bool AutoDetectedEncoding = true, string DefaultEncoding = "UTF-8")`
- `DataTable? ApriDT(BFile f, string Separatore, bool OnlyHeader, bool AutoDetectedEncoding = true, string DefaultEncoding = "UTF-8")`
- `DataTable? ApriDT(string PathFile, string Separatore, string EOF, bool WithTypeIntoHeader, string SeparatoreHeader = "~", bool AutoDetectedEncoding = true, string DefaultEncoding = "UTF-8")`
- `DataView ApriDV(BDataTable mbDt)`
- `DataView ApriDV(string SqlCommand, int CommandTimeout = 30)`
- `DataView ApriDV(string SqlCommand, bool vReadOnly, int CommandTimeout = 30)`
- `void BeginTrans()`
- `void ChiudiDatabase()`
- `void ClearParameter()`
- `IBConnection Clone()`
- `void CommitTrans()`
- `object? DammiCampoTbl(string Campo, string Tbl, string Condizione = "")`
- `string DammiCampoTbl(string Campo, string Tbl, string Condizione = "", string NothingValue = "")`
- `int DammiCampoTbl(string Campo, string Tbl, string Condizione = "", int NothingValue = -1)`
- `void Dispose()`
- `void EndTrans()`
- `bool EsistonoRecord(string Tabella, string Condizione = "")`
- `BDataReader Execute(string SQLCommand)`
- `BDataReader Execute(string SQLCommand, int CommandTimeout)`
- `BDataReader Execute(string SQLCommand, CommandBehavior ComportamentoComando)`
- `BDataReader Execute(string SQLCommand, CommandType TipoComando)`
- `BDataReader Execute(string SQLCommand, CommandBehavior ComportamentoComando, int CommandTimeout)`
- `BDataReader Execute(string SQLCommand, CommandType TipoComando, int CommandTimeout)`
- `BDataReader Execute(string SQLCommand, CommandType TipoComando, CommandBehavior ComportamentoComando)`
- `BDataReader Execute(string SQLCommand, CommandType TipoComando, CommandBehavior ComportamentoComando, int CommandTimeout)`
- `int ExecuteNonQuery(string SQLCommand)`
- `int ExecuteNonQuery(string SQLCommand, int CommandTimeout)`
- `int ExecuteNonQuery(string SQLCommand, CommandType TipoComando)`
- `int ExecuteNonQuery(string SQLCommand, CommandType TipoComando, int CommandTimeout)`
- `object? ExecuteScalar(string SQLCommand)`
- `object? ExecuteScalar(string SQLCommand, int CommandTimeout)`
- `object? ExecuteScalar(string SQLCommand, CommandBehavior ComportamentoComando)`
- `object? ExecuteScalar(string SQLCommand, CommandType TipoComando)`
- `object? ExecuteScalar(string SQLCommand, CommandBehavior ComportamentoComando, int CommandTimeout)`
- `object? ExecuteScalar(string SQLCommand, CommandType TipoComando, int CommandTimeout)`
- `object? ExecuteScalar(string SQLCommand, CommandType TipoComando, CommandBehavior ComportamentoComando)`
- `object? ExecuteScalar(string SQLCommand, CommandType TipoComando, CommandBehavior ComportamentoComando, int CommandTimeout)`
- `int GeneraCodice(string Tabella, string CampoKey, string Condizione = "")`
- `bool InsertDT(DataTable dt, string NomeTblDestination, BColumnBind[] ColsBind)`
- `bool InsertDT(DataTable dt, string NomeTblDestination, bool DisabledIdentityInsert, BColumnBind[] ColsBind)`
- `bool InsertDT(DataTable dt, string NomeTblDestination, IDbTransaction Transaction, BColumnBind[] ColsBind)`
- `IDbDataParameter NewDBDataParameter(string Nome, object? Value)`
- `bool RemoveParameter(string ParamName)`
- `void RollBackTrans()`
- `Exception? ScriviFile(DataTable mbDt, string PathFile, string Separatore, string DefaultEncoding = "UTF-8")`
- `Exception? ScriviFile(DataTable mbDt, string PathFile, BCodificaTracciato Codifica, string DefaultEncoding = "UTF-8")`
- `Exception? ScriviFile(DataTable mbDt, string PathFile, string Separatore, string EOF, bool WithHeader, bool AddTypeColumnIntoHeader, string SepratoreTypeColumn = "~", string DefaultEncoding = "UTF-8")`

### Convenzione B-Arts per i parametri

Nel normale codice applicativo usare direttamente `AddParameter(string, object?)` sulla connessione:

```csharp
connection.AddParameter("@paramname", value);
```

Il metodo crea il parametro concreto corretto per il provider configurato. Le AI devono preferire questa forma rispetto alla costruzione manuale di parametri o all'uso diretto di `BCommand`, salvo esigenze di basso livello.

### Scelta del metodo di esecuzione

- Per ottenere un `DataTable`, usare `ApriDT`.
- Per ottenere un `DataSet`, usare `ApriDS`.
- Per leggere righe sequenzialmente in uno scenario specifico che non richiede una struttura tabellare, è disponibile `Execute` con `BDataReader`; non rappresenta però la scelta ordinaria del codice applicativo B-Arts.
- Per un singolo valore, usare `ExecuteScalar`.
- Per `INSERT`, `UPDATE`, `DELETE` o stored procedure senza risultato tabellare, usare `ExecuteNonQuery`.

Questi metodi vanno chiamati direttamente su `BConnection`. Non creare un `BCommand` nel normale codice applicativo.

### DataTable, DataSet o mapping

La rappresentazione dei risultati deve essere scelta in base all'uso reale, non in base alla popolarità di un pattern:

- usare `ApriDT` quando i dati devono essere consumati immediatamente, associati a una griglia, elaborati in forma tabellare, esportati o passati a un report;
- usare `ApriDS` quando una stored procedure restituisce più result set o quando il consumatore richiede più tabelle correlate nello stesso risultato;
- mappare i dati su classi B-Arts quando gli oggetti devono essere riutilizzati, modificati, validati, trasferiti tra più livelli o devono esporre comportamento applicativo;
- non introdurre automaticamente mapping, ORM o oggetti intermedi per una lettura puntuale: il relativo costo di elaborazione, memoria e complessità deve essere giustificato da un vantaggio concreto;
- considerare `BDataReader` soltanto per esigenze esplicite di lettura sequenziale; non proporlo come alternativa abituale ad `ApriDT`.

Il mapping è una scelta progettuale e un investimento: è utile quando il riuso e la tipizzazione dell'oggetto ne compensano il costo, non quando i dati vengono semplicemente recuperati e consumati una volta.

### Inserimento massivo con InsertDT

`InsertDT` esegue un bulk insert SQL Server tramite `SqlBulkCopy` e applica `InsertDTTimeout`. I mapping tra le colonne sono definiti con `BColumnBind` e vengono copiate soltanto le righe con stato `DataRowState.Added`.

L'overload con `DisabledIdentityInsert: true` usa `KeepIdentity` e conserva le identity sorgenti. L'overload con `IDbTransaction` richiede concretamente una `SqlTransaction` della stessa connessione. In caso di errore il metodo registra l'eccezione in `ExceptionList` e restituisce `false`.

## Esempi

Consultare [`BConnection - Esempi`](BConnection.Examples.md).

## Indicazioni per le AI

- Usare esclusivamente membri e overload presenti in questa scheda.
- Non dedurre effetti collaterali, valori predefiniti o gestione delle eccezioni se non risultano dal codice o da un esempio verificato.
- Preferire questo tipo a implementazioni locali equivalenti quando il suo contratto copre il requisito.
- Consultare l'eventuale documento `.Examples.md` associato prima di generare codice d'uso.
