Vincoli DataTable

I vincoli consentono di applicare restrizioni ai dati di una DataTable, in modo da garantire l'integrità di tali dati. Un vincolo è una regola automatica applicata a una colonna, o a colonne correlate, che consente di determinare le operazioni da eseguire in caso di modifica del valore di una riga. I vincoli vengono applicati se la proprietà System.Data.DataSet.EnforceConstraints dell'oggetto DataSet è impostata su true. Per un esempio di codice che illustra come impostare la proprietà EnforceConstraints, vedere l'argomento relativo a EnforceConstraints.

In ADO.NET sono disponibili due tipi di vincoli: ForeignKeyConstraint e UniqueConstraint. Per impostazione predefinita, entrambi i vincoli vengono creati automaticamente quando si crea una relazione tra due o più tabelle aggiungendo un DataRelation al DataSet. È tuttavia possibile disabilitare questo comportamento impostando createConstraints = false quando si crea la relazione.

ForeignKeyConstraint

Un ForeignKeyConstraint consente di applicare regole relative alla modalità di propagazione di aggiornamenti ed eliminazioni alle tabelle correlate. Ad esempio, se un valore di una riga di una tabella viene aggiornato o eliminato e tale valore viene usato anche in una o più tabelle correlate, un vincolo ForeignKeyConstraint consentirà di determinare gli effetti di tale modifica sulle tabelle correlate.

Mediante le proprietà DeleteRule e UpdateRule di ForeignKeyConstraint è possibile definire l'operazione da eseguire quando un utente tenta di eliminare o aggiornare una riga in una tabella correlata. Nella tabella seguente vengono descritte le diverse impostazioni disponibili per le proprietà DeleteRule e UpdateRule di ForeignKeyConstraint.

Impostazione della regola Descrizione
Cascade Elimina o aggiorna righe correlate.
SetNull Imposta i valori delle righe correlate su DBNull.
SetDefault Imposta i valori delle righe correlate sul valore predefinito.
Nessuno Non viene eseguita alcuna operazione sulle righe correlate. Si tratta dell'impostazione predefinita.

Un vincolo ForeignKeyConstraint consente di limitare, oltre che propagare, le modifiche alle colonne correlate. In base alle proprietà impostate per il vincolo ForeignKeyConstraint di una colonna e nel caso in cui la proprietà EnforceConstraints del DataSet sia impostata su true, l'esecuzione di determinate operazioni sulla riga padre provocherà un'eccezione. Ad esempio, se la proprietà DeleteRule del vincolo ForeignKeyConstraint è impostata su None, non sarà possibile eliminare una riga padre nel caso in cui a tale riga siano associate righe figlio.

È possibile creare un vincolo di chiave esterna tra singole colonne o tra una matrice di colonne usando il costruttore ForeignKeyConstraint e passando l'oggetto ForeignKeyConstraint risultante al metodo Add della proprietà Constraints della tabella, che è un ConstraintCollection. Per creare un ForeignKeyConstraint, è inoltre possibile passare argomenti del costruttore a diversi overload del metodo Add di un ConstraintCollection.

Quando si crea un vincolo ForeignKeyConstraint, è possibile passare i valori DeleteRule e UpdateRule al costruttore come argomenti o impostare tali valori come proprietà, come illustrato nell'esempio seguente (dove il valore DeleteRule è impostato su None).

Dim custOrderFK As ForeignKeyConstraint = New ForeignKeyConstraint("CustOrderFK", _  
  custDS.Tables("CustTable").Columns("CustomerID"), _  
  custDS.Tables("OrdersTable").Columns("CustomerID"))  
custOrderFK.DeleteRule = Rule.None
' Cannot delete a customer value that has associated existing orders.  
custDS.Tables("OrdersTable").Constraints.Add(custOrderFK)  
ForeignKeyConstraint custOrderFK = new ForeignKeyConstraint("CustOrderFK",  
  custDS.Tables["CustTable"].Columns["CustomerID"],
  custDS.Tables["OrdersTable"].Columns["CustomerID"]);  
custOrderFK.DeleteRule = Rule.None;
// Cannot delete a customer value that has associated existing orders.  
custDS.Tables["OrdersTable"].Constraints.Add(custOrderFK);  

AcceptRejectRule

È possibile accettare le modifiche apportate alle righe usando il metodo AcceptChanges o annullare tali modifiche usando il metodo RejectChanges di DataSet, DataTable o DataRow. Se in un DataSet sono contenuti vincoli ForeignKeyConstraints, la chiamata dei metodi AcceptChanges o RejectChanges provocherà l'applicazione di AcceptRejectRule. La proprietà AcceptRejectRule del vincolo ForeignKeyConstraint consente di determinare l'operazione da eseguire nelle righe figlio quando il metodo AcceptChanges o RejectChanges viene chiamato nella riga padre.

Nella tabella seguente sono elencate le impostazioni disponibili per AcceptRejectRule.

Impostazione della regola Descrizione
Cascade Consente di accettare o rifiutare le modifiche alle righe figlio.
Nessuno Non viene eseguita alcuna operazione sulle righe figlio. Si tratta dell'impostazione predefinita.

Esempio

Nell'esempio seguente viene creato un oggetto ForeignKeyConstraint, ne vengono impostate alcune proprietà, tra cui AcceptRejectRule, nonché viene aggiunto all'oggetto ConstraintCollection di un oggetto DataTable.

static void CreateConstraint(DataSet dataSet,
    string table1, string table2, string column1, string column2)
{
    // Declare parent column and child column variables.
    DataColumn parentColumn, childColumn;
    ForeignKeyConstraint foreignKeyConstraint;

    // Set parent and child column variables.
    parentColumn = dataSet.Tables[table1]?.Columns[column1] ??
        throw new NullReferenceException($"{nameof(CreateConstraint)}: {table1}.{column1} not found");
    childColumn = dataSet.Tables[table2]?.Columns[column2] ??
        throw new NullReferenceException($"{nameof(CreateConstraint)}: {table2}.{column2} not found");
    foreignKeyConstraint = new ForeignKeyConstraint
       ("SupplierForeignKeyConstraint", parentColumn, childColumn)
    {
        // Set null values when a value is deleted.
        DeleteRule = Rule.SetNull,
        UpdateRule = Rule.Cascade,
        AcceptRejectRule = AcceptRejectRule.None
    };

    // Add the constraint, and set EnforceConstraints to true.
    dataSet.Tables[table1]?.Constraints.Add(foreignKeyConstraint);
    dataSet.EnforceConstraints = true;
}
Private Sub CreateConstraint(dataSet As DataSet, _
   table1 As String, table2 As String, _
   column1 As String, column2 As String)

    ' Declare parent column and child column variables.
    Dim parentColumn As DataColumn
    Dim childColumn As DataColumn
    Dim foreignKeyConstraint As ForeignKeyConstraint

    ' Set parent and child column variables.
    parentColumn = dataSet.Tables(table1).Columns(column1)
    childColumn = dataSet.Tables(table2).Columns(column2)
    foreignKeyConstraint = New ForeignKeyConstraint _
       ("SupplierForeignKeyConstraint", parentColumn, childColumn)

    ' Set null values when a value is deleted.
    foreignKeyConstraint.DeleteRule = Rule.SetNull
    foreignKeyConstraint.UpdateRule = Rule.Cascade
    foreignKeyConstraint.AcceptRejectRule = AcceptRejectRule.None

    ' Add the constraint, and set EnforceConstraints to true.
    dataSet.Tables(table1).Constraints.Add(foreignKeyConstraint)
    dataSet.EnforceConstraints = True
End Sub

UniqueConstraint

L'oggetto UniqueConstraint, che può essere assegnato a una singola colonna o a una matrice di colonne in un oggetto DataTable, consente di assicurare che tutti i dati della colonna o delle colonne specificate siano univoci in ogni riga. È possibile creare un vincolo univoco per una colonna o una matrice di colonne usando il costruttore UniqueConstraint e passando l'oggetto UniqueConstraint risultante al metodo Add della proprietà Constraints della tabella, che è un ConstraintCollection. Per creare un UniqueConstraint, è inoltre possibile passare argomenti del costruttore a diversi overload del metodo Add di un ConstraintCollection. Quando si crea un vincolo UniqueConstraint per una o più colonne, è possibile, se lo si desidera, specificare se la colonna o le colonne sono una chiave primaria.

È anche possibile creare un vincolo univoco per una colonna impostando la proprietà Unique della colonna su true. In alternativa, per rimuovere eventuali vincoli univoci esistenti, è possibile impostare la proprietà Unique di una singola colonna su false. La definizione di una o più colonne come chiave primaria per una tabella consentirà di creare automaticamente un vincolo univoco per la colonna o le colonne specificate. Se si rimuove una colonna dalla proprietà PrimaryKey di una DataTable, il vincolo UniqueConstraint verrà rimosso.

L'esempio seguente consente di creare un vincolo UniqueConstraint per due colonne di una DataTable.

Dim custTable As DataTable = custDS.Tables("Customers")  
Dim custUnique As UniqueConstraint = _  
    New UniqueConstraint(New DataColumn()   {custTable.Columns("CustomerID"), _  
    custTable.Columns("CompanyName")})  
custDS.Tables("Customers").Constraints.Add(custUnique)  
DataTable custTable = custDS.Tables["Customers"];  
UniqueConstraint custUnique = new UniqueConstraint(new DataColumn[]
    {custTable.Columns["CustomerID"],
    custTable.Columns["CompanyName"]});  
custDS.Tables["Customers"].Constraints.Add(custUnique);  

Vedi anche