Generazione di comandi SQL di modificaModification SQL Generation

Questa sezione descrive come sviluppare un modulo di generazione SQL di modifica per il provider (database conforme a SQL:1999).This section discusses how to develop a modification SQL generation module for your (SQL:1999-compliant database) provider. Tale modulo è responsabile della conversione di un albero dei comandi di modifica nelle istruzioni SQL INSERT, UPDATE o DELETE appropriate.This module is responsible for translating a modification command tree into the appropriate SQL INSERT, UPDATE or DELETE statements.

Per informazioni sulla generazione SQL per le istruzioni select, vedere generazione SQL.For information about SQL generation for select statements, see SQL Generation.

Panoramica degli alberi dei comandi di modificaOverview of Modification Command Trees

Il modulo di generazione SQL di modifica genera istruzioni SQL di modifica specifiche del database basate su un determinato DbModificationCommandTree di input.The modification SQL generation module generates database-specific modification SQL statements based on a given input DbModificationCommandTree.

Un oggetto DbModificationCommandTree è una rappresentazione del modello a oggetti di un'operazione DML di modifica (inserimento, aggiornamento o eliminazione), che eredita da DbCommandTree.A DbModificationCommandTree is an object model representation of a modification DML operation (an insert, an update, or a delete operation), inheriting from DbCommandTree. Esistono tre implementazioni di DbModificationCommandTree:There are three implementations of DbModificationCommandTree:

  • DbInsertCommandTreeDbInsertCommandTree

  • DbUpdateCommandTreeDbUpdateCommandTree

  • DbDeleteCommandTreeDbDeleteCommandTree

DbModificationCommandTree e le relative implementazioni generate dal Entity FrameworkEntity Framework rappresentano sempre un'operazione singola riga.DbModificationCommandTree and its implementations that are produced by the Entity FrameworkEntity Framework always represent a single row operation. Questa sezione descrive questi tipi con i relativi vincoli in .NET Framework versione 3.5.This section describes these types with their constraints in the .NET Framework version 3.5.

DiagramDiagram

DbModificationCommandTree include una proprietà Target che rappresenta il set di destinazioni per l'operazione di modifica.DbModificationCommandTree has a Target property that represents the target set for the modification operation. La proprietà Expression di Target, che definisce il set di input, è sempre DbScanExpression.The Target’s Expression property, which defines the input set is always DbScanExpression. Un oggetto DbScanExpression può rappresentare una tabella o una vista o un set di dati definito con una query se la proprietà di metadati "Definizione di Query" di destinazione è diverso da null.A DbScanExpression can either represent a table or a view, or a set of data defined with a query if the metadata property "Defining Query" of its Target is non-null.

Un oggetto DbScanExpression che rappresenta una query può raggiungere un provider come destinazione della modifica solo se il set è stato definito tramite una query di definizione nel modello, ma non è stata specificata alcuna funzione per la corrispondente operazione di modifica.A DbScanExpression that represents a query could only reach a provider as a target of modification if the set was defined by using a defining query in the model but no function was provided for the corresponding modification operation. È possibile che alcuni provider non siano in grado di supportare tale scenario, ad esempio SqlClient.Providers may not be able to support such a scenario (SqlClient, for example, does not).

DbInsertCommandTree rappresenta un'operazione di inserimento di una singola riga espressa come albero dei comandi.DbInsertCommandTree represents a single row insert operation expressed as a command tree.

public sealed class DbInsertCommandTree : DbModificationCommandTree {  
   public IList<DbModificationClause> SetClauses { get }  
   public DbExpression Returning { get }  
}  

DbUpdateCommandTree rappresenta un'operazione di aggiornamento di una singola riga espressa come albero dei comandi.DbUpdateCommandTree represents a single-row update operation expressed as a command tree.

DbDeleteCommandTree rappresenta un'operazione di eliminazione di una singola riga espressa come albero dei comandi.DbDeleteCommandTree represents a single row delete operation expressed as a command tree.

Restrizioni sulle proprietà degli alberi dei comandi di modificaRestrictions on Modification Command Tree Properties

Le informazioni e le restrizioni seguenti si applicano alle proprietà degli alberi dei comandi di modifica.The following information and restrictions apply to the modification command tree properties.

Returning in DbInsertCommandTree e DbUpdateCommandTreeReturning in DbInsertCommandTree and DbUpdateCommandTree

Quando è diversa da null, la proprietà Returning indica che il comando restituisce un lettore.When non-null, Returning indicates that the command returns a reader. In caso contrario, il comando deve restituire un valore scalare che indica il numero di righe interessate (inserite o aggiornate).Otherwise, the command should return a scalar value indicating the number of rows affected (inserted or updated).

Il valore Returning specifica una proiezione dei risultati da restituire in base alla riga inserita o aggiornata.The Returning value specifies a projection of results to be returned based on the inserted or the updated row. Può essere solo del tipo DbNewInstanceExpression che rappresenta una riga i cui argomenti sono oggetti DbPropertyExpression di un oggetto DbVariableReferenceExpression che rappresenta un riferimento alla proprietà Target dell'oggetto DbModificationCommandTree corrispondente.It can only be of type DbNewInstanceExpression representing a row, with each of its arguments being a DbPropertyExpression over a DbVariableReferenceExpression representing a reference to the Target of the corresponding DbModificationCommandTree. Le proprietà rappresentate da DbPropertyExpressions e usate nella proprietà Returning sono sempre valori generati dall'archivio o calcolati.The properties represented by the DbPropertyExpressions used in the property Returning are always store generated or computed values. In DbInsertCommandTree la proprietà Returning non è null quando almeno una proprietà della tabella in cui viene inserita la riga viene specificata come generata dall'archivio o calcolata (contrassegnata come StoreGeneratedPattern.Identity o StoreGeneratedPattern.Computed in ssdl).In DbInsertCommandTree, Returning is not null when at least one property of the table in which the row is being inserted is specified as store generated or computed (marked as StoreGeneratedPattern.Identity or StoreGeneratedPattern.Computed in the ssdl). In DbUpdateCommandTrees la proprietà Returning non è null quando almeno una proprietà della tabella in cui viene aggiornata la riga viene specificata come generata dall'archivio o calcolata (contrassegnata come StoreGeneratedPattern.Identity o StoreGeneratedPattern.Computed in ssdl).In DbUpdateCommandTrees, Returning is not null when at least one property of the table in which the row is being updated is specified as store computed (marked as StoreGeneratedPattern.Computed in the ssdl).

SetClauses in DbInsertCommandTree e DbUpdateCommandTreeSetClauses in DbInsertCommandTree and DbUpdateCommandTree

SetClauses specifica l'elenco di clausole SET di inserimento o di aggiornamento che definiscono l'operazione di inserimento o aggiornamento.SetClauses specifies the list of insert or update set clauses that define the insert or update operation.

The elements of the list are specified as type DbModificationClause, which specifies a single clause in an insert or update modification operation. DbSetClause inherits from DbModificationClause and specifies the clause in a modification operation that sets the value of a property. Beginning in version 3.5 of the .NET Framework, all elements in SetClauses are of type SetClause.   

Property specifica la proprietà che deve essere aggiornata.Property specifies the property that should be updated. È sempre un oggetto DbPropertyExpression di un oggetto DbVariableReferenceExpression, che rappresenta un riferimento alla proprietà Target del corrispondente DbModificationCommandTree.It is always a DbPropertyExpression over a DbVariableReferenceExpression, which represents a reference to the Target of the corresponding DbModificationCommandTree.

Value specifica il nuovo valore con cui aggiornare la proprietà.Value specifies the new value with which to update the property. È di tipo DbConstantExpression o DbNullExpression.It is either of type DbConstantExpression or DbNullExpression.

Predicate in DbUpdateCommandTree e DbDeleteCommandTreePredicate in DbUpdateCommandTree and DbDeleteCommandTree

Predicate specifica il predicato usato per determinare i membri della raccolta di destinazione da aggiornare o eliminare.Predicate specifies the predicate used to determine which members of the target collection should be updated or deleted. Si tratta di un albero delle espressioni costituito dal subset di DbExpression seguente:It is an expression tree built of the following subset of DbExpressions:

  • DbComparisonExpression del tipo Equals, con l'elemento figlio di destra che corrisponde a un oggetto DbPropertyExpression secondo le restrizioni indicate di seguito e l'elemento figlio di sinistra che corrisponde a un oggetto DbConstantExpression.DbComparisonExpression of kind Equals, with the right child being a DbPropertyExression as restricted below and the left child a DbConstantExpression.

  • DbConstantExpressionDbConstantExpression

  • DbIsNullExpression su un oggetto DbPropertyExpression secondo le restrizioni indicate di seguitoDbIsNullExpression over a DbPropertyExpresison as restricted below

  • DbPropertyExpression su un oggetto DbVariableReferenceExpression che rappresenta un riferimento alla proprietà Target del corrispondente DbModificationCommandTree.DbPropertyExpression over a DbVariableReferenceExpression representing a reference to the Target of the corresponding DbModificationCommandTree.

  • DbAndExpressionDbAndExpression

  • DbNotExpressionDbNotExpression

  • DbOrExpressionDbOrExpression

Generazione di comandi SQL di modifica nel provider di esempioModification SQL Generation in the Sample Provider

Il Provider di esempio Entity Framework illustra i componenti dei provider di dati ADO.NET che supportano il Entity FrameworkEntity Framework.The Entity Framework Sample Provider demonstrates the components of ADO.NET Data Providers that support the Entity FrameworkEntity Framework. È destinato a un database SQL Server 2005 e viene implementato come wrapper basato sul provider di dati ADO.NET 2.0 System.Data.SqlClient.It targets a SQL Server 2005 database and is implemented as a wrapper on top of System.Data.SqlClient ADO.NET 2.0 Data Provider.

Il modulo di generazione SQL di modifica del provider di esempio (disponibile nel file SQL Generation\DmlSqlGenerator.cs) accetta un oggetto DbModificationCommandTree di input e produce una singola istruzione SQL di modifica, eventualmente seguita da un'istruzione Select per restituire un lettore se specificato da DbModificationCommandTree.The modification SQL generation module of the sample provider (located in the file SQL Generation\DmlSqlGenerator.cs) takes an input DbModificationCommandTree and produces a single modification SQL statement possibly followed by a select statement to return a reader if specified by the DbModificationCommandTree. Tenere presente che la forma dei comandi generati dipende dal database SQL Server di destinazione.Note that the shape of the commands generated is affected by the target SQL Server database.

Classi helper: ExpressionTranslatorHelper Classes: ExpressionTranslator

ExpressionTranslator funge da comune convertitore con funzioni di base per tutte le proprietà dell'albero dei comandi di modifica di tipo DbExpression.ExpressionTranslator serves as a common lightweight translator for all modification command tree properties of type DbExpression. Supporta solo la conversione dei tipi di espressione ai quali sono vincolate le proprietà dell'albero dei comandi di modifica ed è stato creato tenendo conto di tali vincoli.It supports translation of only the expression types to which the properties of the modification command tree are constrained and is built with the particular constraints in mind.

Nelle informazioni seguenti viene descritta la visita di specifici tipi di espressione (i nodi con conversioni semplici vengono omessi).The following information discusses visiting specific expression types (nodes with trivial translations are omitted).

DbComparisonExpressionDbComparisonExpression

Quando ExpressionTranslator viene costruito con preserveMemberValues = true e quando la costante a destra è un oggetto DbConstantExpression (anziché DbNullExpression), associa l'operando di sinistra (un oggetto DbPropertyExpression) a tale DbConstantExpression.When the ExpressionTranslator is constructed with preserveMemberValues = true, and when the constant to the right is a DbConstantExpression (instead of DbNullExpression), it associates the left operand (a DbPropertyExpressions) with that DbConstantExpression. Quest'ultimo viene usato se è necessario generare un'istruzione Select di restituzione per identificare la riga interessata.That is used if a return Select statement needs to be generated to identify the affected row.

DbConstantExpressionDbConstantExpression

Per ogni costante visitata viene creato un parametro.For each visited constant a parameter is created.

DbPropertyExpressionDbPropertyExpression

Poiché l'istanza di DbPropertyExpression rappresenta sempre la tabella di input, a meno che la generazione non abbia creato un alias (cosa che avviene solo negli scenari di aggiornamento quando viene usata una variabile di tabella), non è necessario specificare alcun alias per l'input. La conversione assume il nome di proprietà predefinito.Given that the Instance of the DbPropertyExpression always represents the input table, unless the generation has created an alias (which only happens in update scenarios when a table variable is used), no alias needs to be specified for the input; the translation defaults to the property name.

Generazione di un comando SQL di inserimentoGenerating an Insert SQL Command

Per un determinato DbInsertCommandTree nel provider di esempio, il comando di inserimento generato si basa su uno dei due modelli di inserimento riportati di seguito.For a given DbInsertCommandTree in the sample provider, the generated insert command follows one of the two insert templates below.

Il primo modello presenta un comando per l'esecuzione dell'inserimento in base ai valori dell'elenco di SetClauses e un'istruzione SELECT per la restituzione delle proprietà specificate nella proprietà Returning della riga inserita se la proprietà Returning non è null.The first template has a command to perform the insert given the values in the list of SetClauses, and a SELECT statement to return the properties specified in the Returning property for the inserted row if the Returning property was not null. L'elemento predicato "@ @ROWCOUNT > 0" è true se è stata inserita una riga.The predicate element "@@ROWCOUNT > 0" is true if a row was inserted. L'elemento predicato "keyMemberI = keyValueI | SCOPE_IDENTITY ()" assume la forma "keyMemberI = SCOPE_IDENTITY ()" solo se keyMemeberI è una chiave generata dall'archivio, in quanto SCOPE_IDENTITY () restituisce l'ultimo valore identity inserito in un'identità ( colonna generata dall'archivio).The predicate element "keyMemberI = keyValueI | scope_identity()" takes the shape "keyMemberI = scope_identity()" only if keyMemeberI is a store-generated key, because scope_identity() returns the last identity value inserted into an identity (store-generated) column.

-- first insert Template  
INSERT <target>   [ (setClauseProperty0, .. setClausePropertyN)]    
VALUES (setClauseValue0, .. setClauseValueN) |  DEFAULT VALUES   

[SELECT <returning>   
 FROM <target>  
 WHERE @@ROWCOUNT > 0 AND keyMember0 = keyValue0 AND .. keyMemberI =  keyValueI | scope_identity()  .. AND  keyMemberN = keyValueN]  

Il secondo modello è necessario se il comando Insert specifica l'inserimento di una riga in cui la chiave primaria è generata dall'archivio ma non è un tipo Integer e pertanto non può essere usata con scope_identity()).The second template is needed if the insert specifies inserting a row where the primary key is store-generated but is not an integer type and therefore can't be used with scope_identity()). Viene usato anche in presenza di una chiave composta generata dall'archivio.It is also used if there is a compound store-generated key.

-- second insert template  
DECLARE @generated_keys TABLE [(keyMember0, … keyMemberN)  

INSERT <target>   [ (setClauseProperty0, .. setClausePropertyN)]    
 OUTPUT inserted.KeyMember0, …, inserted.KeyMemberN INTO @generated_keys  
 VALUES (setClauseValue0, .. setClauseValueN) |  DEFAULT VALUES  

[SELECT <returning_over_t>   
 FROM @generated_keys  AS g  
JOIN <target> AS t ON g.KeyMember0 = t.KeyMember0 AND … g.KeyMemberN = t.KeyMemberN  
 WHERE @@ROWCOUNT > 0  

Nell'esempio riportato di seguito viene usato il modello incluso nel provider di esempio.The following is an example that uses the model that is included with the sample provider. Viene generato un comando di inserimento da un oggetto DbInsertCommandTree.It generates an insert command from a DbInsertCommandTree.

Nel codice seguente viene inserito un oggetto Category:The following code inserts a Category:

using (NorthwindEntities northwindContext = new NorthwindEntities()) {  
   Category c = new Category();  
   c.CategoryName = "Test Category";  
   c.Description = "A new category for testing";  
   northwindContext.AddObject("Categories", c);  
   northwindContext.SaveChanges();  
}  

In questo codice viene prodotto il seguente albero dei comandi passato al provider:This code produces the following command tree, which is passed to the provider:

DbInsertCommandTree  
|_Parameters  
|_Target : 'target'  
| |_Scan : dbo.Categories  
|_SetClauses  
| |_DbSetClause  
| | |_Property  
| | | |_Var(target).CategoryName  
| | |_Value  
| |   |_'Test Category'  
| |_DbSetClause  
| | |_Property  
| | | |_Var(target).Description  
| | |_Value  
| |   |_'A new category for testing'  
| |_DbSetClause  
|   |_Property  
|   | |_Var(target).Picture  
|   |_Value  
|     |_null  
|_Returning  
  |_NewInstance : Record['CategoryID'=Edm.Int32]  
    |_Column : 'CategoryID'  
      |_Var(target).CategoryID  

Il comando di archiviazione prodotto dal provider di esempio è l'istruzione SQL seguente:The store command that the sample provider produces is the following SQL statement:

insert [dbo].[Categories]([CategoryName], [Description], [Picture])  
values (@p0, @p1, null)  
select [CategoryID]  
from [dbo].[Categories]  
where @@ROWCOUNT > 0 and [CategoryID] = scope_identity()  

Generazione di un comando SQL di aggiornamentoGenerating an Update SQL Command

Per un determinato DbUpdateCommandTree, il comando di aggiornamento generato si basa sul modello seguente:For a given DbUpdateCommandTree, the generated update command is based on the following template:

-- UPDATE Template   
UPDATE <target>   
SET setClauseProprerty0 = setClauseValue0,  .. setClauseProprertyN = setClauseValueN  | @i = 0  
WHERE <predicate>  

[SELECT <returning>   
 FROM <target>  
 WHERE @@ROWCOUNT > 0 AND keyMember0 = keyValue0 AND .. keyMemberI =  keyValueI | scope_identity()  .. AND  keyMemberN = keyValueN]  

La clausola set include la clausola set falsa ("@i = 0") solo se non vengono specificate clausole set.The set clause has the fake set clause ("@i = 0") only if no set clauses are specified. In questo modo si garantisce che le colonne calcolate dall'archivio vengano ricalcolate.This is to ensure that any store-computed columns are recomputed.

Solo se la proprietà Returning non è null, viene generata un'istruzione Select per restituire le proprietà specificate nella proprietà Returning.Only if the Returning property is not null, a select statement is generated to return the properties specified in the Returning property.

Nell'esempio riportato di seguito viene usato il modello incluso nel provider di esempio per generare un comando di aggiornamento.The following example uses the model that is included with the sample provider to generate an update command.

Nel codice utente seguente viene aggiornato un oggetto Category:The following user code updates a Category:

using (NorthwindEntities northwindContext = new NorthwindEntities()) {  
   Category c = northwindContext.Categories.Where(i => i.CategoryName == "Test Category").First();  
   c.CategoryName = "New test name";  
   northwindContext.SaveChanges();  
}  

In questo codice utente viene prodotto il seguente albero dei comandi passato al provider:This user code produces the following command tree, which is passed to the provider:

DbUpdateCommandTree  
|_Parameters  
|_Target : 'target'  
| |_Scan : dbo.Categories  
|_SetClauses  
| |_DbSetClause  
|   |_Property  
|   | |_Var(target).CategoryName  
|   |_Value  
|     |_'New test name'  
|_Predicate  
| |_  
|   |_Var(target).CategoryID  
|   |_=  
|   |_10  
|_Returning   

Il provider di esempio produce il comando di archiviazione seguente:The sample provider produces the following store command:

update [dbo].[Categories]  
set [CategoryName] = @p0  
where ([CategoryID] = @p1)   

Generazione di un comando SQL di eliminazioneGenerating a Delete SQL Command

Per un determinato DbDeleteCommandTree, il comando DELETE generato si basa sul modello seguente:For a given DbDeleteCommandTree, the generated DELETE command is based on the following template:

-- DELETE Template   
DELETE <target>   
WHERE <predicate>  

Nell'esempio riportato di seguito viene usato il modello incluso nel provider di esempio per generare un comando di eliminazione.The following example uses the model that is included with the sample provider to generate a delete command.

Nel codice utente seguente viene eliminato un oggetto Category:The following user code deletes a Category:

using (NorthwindEntities northwindContext = new NorthwindEntities()) {  
   Category c = northwindContext.Categories.Where(i => i.CategoryName == "New test name").First();  
   northwindContext.DeleteObject(c);  
   northwindContext.SaveChanges();  
}  

In questo codice utente viene prodotto il seguente albero dei comandi passato al provider:This user code produces the following command tree, which is passed to the provider.

DbDeleteCommandTree  
|_Parameters  
|_Target : 'target'  
| |_Scan : dbo.Categories  
|_Predicate  
  |_  
    |_Var(target).CategoryID  
    |_=  
    |_10  

Il provider di esempio produce il comando di archiviazione seguente:The following store command is produced by the sample provider:

delete [dbo].[Categories]  
where ([CategoryID] = @p0)  

Vedere ancheSee Also

Scrittura di un provider di dati Entity FrameworkWriting an Entity Framework Data Provider