Procedure consigliate per la generazione di SQL dagli alberi dei comandiGenerating SQL from Command Trees - Best Practices

Gli alberi dei comandi di query di output sono molto simili alle query esprimibili in SQL.Output query command trees closely model queries expressible in SQL. Per generare SQL da un albero dei comandi di output, tuttavia i writer del provider devono affrontare alcune difficoltà comuni.However, there are certain common challenges for provider writers when generating SQL from an output command tree. In questo argomento vengono illustrate tali difficoltà, mentreThis topic discusses these challenges. nell'argomento successivo il provider di esempio mostra come risolverle.In the next topic, the sample provider shows how to address these challenges.

Nodi DbExpression di gruppo in un'istruzione SQL SELECTGroup DbExpression Nodes in a SQL SELECT Statement

Un'istruzione SQL tipica presenta una struttura annidata della forma seguente:A typical SQL statement has a nested structure of the following shape:

SELECT …  
FROM …  
WHERE …  
GROUP BY …  
ORDER BY …  

Una o più clausole potrebbero essere vuote.One or more clauses may be empty. In qualsiasi riga potrebbe essere presente un'istruzione SELECT annidata.A nested SELECT statement could occur in any of the lines.

Una possibile conversione di un albero dei comandi delle query in un'istruzione SQL SELECT produrrebbe una sottoquery per ogni operatore relazionale.A possible translation of a query command tree into a SQL SELECT statement would produce one subquery for every relational operator. Ciò comporterebbe tuttavia la creazione di sottoquery annidate non necessarie e di difficile lettura.However, that would lead to unnecessary nested subqueries that would be difficult to read. Per alcuni archivi dati le prestazioni delle query potrebbero essere scarse.On some data stores, the query may perform poorly.

Si consideri, come esempio, l'albero dei comandi di query seguenteAs an example, consider the following query command tree

Project (  
a.x,  
   a = Filter(  
      b.y = 5,   
      b = Scan("TableA")  
   )  
)  

Una conversione non efficace produrrebbe:An inefficient translation would produce:

SELECT a.x  
FROM (   SELECT *  
         FROM TableA as b  
         WHERE b.y = 5) as a  

Si osservi come ogni nodo dell'espressione relazionale diventa una nuova istruzione SQL SELECT.Note that every relational expression node becomes a new SQL SELECT statement.

Pertanto, è importante aggregare il maggior numero di nodi dell'espressione possibile in una sola istruzione SQL SELECT senza compromettere la correttezza.Therefore, it is important to aggregate as many expression nodes as possible into a single SQL SELECT statement while preserving correctness.

Il risultato di un'aggregazione di questo tipo per l'esempio sopra presentato sarebbe:The result of such aggregation for the example presented above would be:

SELECT b.x   
FROM TableA as b  
WHERE b.y = 5  

Rendere bidimensionali i join in un'istruzione SQL SELECTFlatten Joins in a SQL SELECT Statement

Un caso di aggregazione di più nodi in un'unica istruzione SQL SELECT consiste nell'aggregazione di più espressioni di join in un'unica istruzione SQL SELECT.One case of aggregating multiple nodes into a single SQL SELECT statement is aggregating multiple join expressions into a single SQL SELECT statement. DbJoinExpression rappresenta un unico join tra due input.DbJoinExpression represents a single join between two inputs. È tuttavia possibile specificare più di un join come parte di un'unica istruzione SQL SELECT.However, as part of a single SQL SELECT statement, more than one join can be specified. In questo caso i join vengono eseguiti nell'ordine specificato.In that case the joins are performed in the order specified.

I join del lato sinistro, ovvero quelli che vengono visualizzati come join figlio a sinistra di un altro join, possono essere più facilmente resi bidimensionali in un'unica istruzione SQL SELECT.Left spine joins, (joins that appear as a left child of another join) can be more easily flattened into a single SQL SELECT statement. Si consideri, come esempio, l'albero dei comandi di query seguente:For example, consider the following query command tree:

InnerJoin(  
   a = LeftOuterJoin(  
   b = Extent("TableA")  
   c = Extent("TableB")  
   ON b.y = c.x ),  
   d = Extent("TableC")   
   ON a.b.y = d.z  
)  

Tale struttura può essere convertita correttamente in:This can be correctly translated into:

SELECT *  
FROM TableA as b  
LEFT OUTER JOIN TableB as c ON b.y = c.x  
INNER JOIN TableC as d ON b.y = d.z  

I join non di sinistra non possono tuttavia essere facilmente resi bidimensionali e non è consigliabile provare a eseguire questa operazione.However, non-left spine joins cannot easily be flattened, and you should not try to flatten them. Ad esempio, i join dell'albero dei comandi di query seguente:For example, the joins in the following query command tree:

InnerJoin(  
   a = Extent("TableA")   
   b = LeftOuterJoin(  
   c = Extent("TableB")  
   d = Extent("TableC")  
   ON c.y = d.x),  
   ON a.z = b.c.y  
)  

Verrebbero convertiti in un'istruzione SQL SELECT con una sottoquery.Would be translated to a SQL SELECT statement with a sub-query.

SELECT *  
FROM TableA as a  
INNER JOIN (SELECT *   
   FROM TableB as c   
   LEFT OUTER JOIN TableC as d  
   ON c.y = d.x) as b  
ON b.y = d.z  

Reindirizzamento degli alias di inputInput Alias Redirecting

Per comprendere il reindirizzamento degli alias di input, si consideri la struttura delle espressioni relazionali, ad esempio DbFilterExpression, DbProjectExpression, DbCrossJoinExpression, DbJoinExpression, DbSortExpression, DbGroupByExpression, DbApplyExpression e DbSkipExpression.To explain input alias redirecting, consider the structure of the relational expressions, such as DbFilterExpression, DbProjectExpression, DbCrossJoinExpression, DbJoinExpression, DbSortExpression, DbGroupByExpression, DbApplyExpression, and DbSkipExpression.

Per ognuno di questi tipi sono disponibili una o più proprietà Input che descrivono una raccolta di input e, per rappresentare ogni elemento di tale input durante un attraversamento della raccolta, viene usata una variabile di associazione che corrisponde a ogni input.Each of these types has one or more Input properties that describe an input collection, and a binding variable corresponding to each input is used to represent each element of that input during a collection traversal. La variabile di associazione viene usata quando si fa riferimento all'elemento di input, ad esempio nella proprietà Predicate di un oggetto DbFilterExpression o nella proprietà Projection di un oggetto DbProjectExpression.The binding variable is used when referring to the input element, for example in the Predicate property of a DbFilterExpression or the Projection property of a DbProjectExpression.

Quando si aggregano più nodi dell'espressione relazionale in una sola istruzione SQL SELECT e si valuta un'espressione che fa parte di un'espressione relazionale, ad esempio parte della proprietà Projection di un oggetto DbProjectExpression, la variabile di associazione usata potrebbe non corrispondere all'alias dell'input, in quanto più associazioni di espressioni dovrebbero essere reindirizzate a un solo extent.When aggregating more relational expression nodes into a single SQL SELECT statement, and evaluating an expression that is part of a relational expression (for example part of the Projection property of a DbProjectExpression) the binding variable that it uses may not be the same as the alias of the input, as multiple expression bindings would have to be redirected to a single extent. Questo problema viene definito ridenominazione degli alias.This problem is called alias renaming.

Si consideri il primo esempio di questo argomento.Consider the first example in this topic. Se si esegue la conversione semplice e si converte Projection a.x (DbPropertyExpression(a, x)), è corretto convertirlo in a.x, in quanto all'input è stato associato l'alias "a" per creare corrispondenza con la variabile di associazione.If doing the naïve translation and translating the Projection a.x (DbPropertyExpression(a, x)), it is correct to translate it into a.x because we have aliased the input as "a" to match the binding variable. Quando tuttavia si aggregano entrambi i nodi in un'unica istruzione SQL SELECT, è necessario convertire lo stesso oggetto DbPropertyExpression in b.x, in quanto all'input è stato associato l'alias "b".However, when aggregating both the nodes into a single SQL SELECT statement, you need to translate the same DbPropertyExpression into b.x, as the input has been aliased with "b".

Bidimensionalità degli alias di joinJoin Alias Flattening

A differenza di qualsiasi altra espressione relazionale di un albero dei comandi di output, DbJoinExpression restituisce un tipo di risultato costituito da una riga formata da due colonne, ognuna delle quali corrisponde a uno degli input.Unlike any other relational expression in an output command tree, the DbJoinExpression outputs a result type that is a row consisting of two columns, each of which corresponds to one of the inputs. La compilazione di un oggetto DbPropertyExpresssion per l'accesso a una proprietà scalare che proviene da un join viene eseguita su un altro oggetto DbPropertyExpresssion.When a DbPropertyExpresssion is built to access a scalar property originating from a join, it is over another DbPropertyExpresssion.

Gli esempi includono "a.b.y" nell'esempio 2 e "b.c.y" nell'esempio 3.Examples include "a.b.y" in example 2 and "b.c.y" in example 3. Nelle istruzioni SQL corrispondenti tuttavia vi si fa riferimento come a "b.y".However in the corresponding SQL statements these are referred as "b.y". Questa nuova assegnazione degli alias viene denominata bidimensionalità degli alias di join.This re-aliasing is called join alias flattening.

Ridenominazione dei nomi di colonna e degli alias degli extentColumn Name and Extent Alias Renaming

Se è necessario completare con una proiezione una query SQL SELECT che presenta un join, quando si enumerano tutte le colonne coinvolte dagli input, è possibile che si verifichi un conflitto di nomi, in quanto più input potrebbero avere lo stesso nome di colonna.If a SQL SELECT query that has a join has to be completed with a projection, when enumerating all the participating columns from the inputs, a name collision may occur, as more than one input may have the same column name. Usare un nome diverso per la colonna per evitare il conflitto.Use a different name for the column to avoid the collision.

Inoltre, quando si rendono bidimensionali i join, è possibile che si verifichi un conflitto tra gli alias delle tabelle coinvolte (o sottoquery). In questo caso, è necessario rinominarle.Also, when flattening joins, participating tables (or subqueries) may have colliding aliases in which case these need to be renamed.

Evitare SELECT *Avoid SELECT *

Non usare SELECT * per effettuare la selezione dalle tabelle di base.Do not use SELECT * to select from base tables. Il modello di archiviazione in un Entity FrameworkEntity Framework applicazione può includere solo un subset di colonne presenti nella tabella di database.The storage model in an Entity FrameworkEntity Framework application may only include a subset of the columns that are in the database table. In questo caso, è possibile che SELECT * produca un risultato errato.In this case, SELECT * may produce an incorrect result. Al contrario, è necessario specificare tutte le colonne coinvolte tramite i nomi di colonna del tipo di risultato delle espressioni interessate.Instead, you should specify all participating columns by using the column names from the result type of the participating expressions.

Riutilizzo delle espressioniReuse of Expressions

È possibile riutilizzare le espressioni nella struttura ad albero dei comandi di query passata da Entity FrameworkEntity Framework.Expressions may be reused in the query command tree passed by the Entity FrameworkEntity Framework. Non presupporre che ogni espressione sia visualizzata solo una volta nella struttura ad albero dei comandi di query.Do not assume that each expression appears only once in the query command tree.

Mapping di tipi primitiviMapping Primitive Types

Quando si esegue il mapping di tipi concettuali (EDM) ai tipi di provider, è necessario eseguire il mapping al tipo più ampio (Int32), in modo che sia possibile adattare tutti i valori possibili.When mapping conceptual (EDM) types to provider types, you should map to the widest type (Int32) so that all possible values fit. Inoltre, evitare di mapping a tipi che non può essere usato per molte operazioni, come i tipi BLOB (ad esempio, ntext in SQL Server).Also, avoid mapping to types that cannot be used for many operations, like BLOB types (for example, ntext in SQL Server).

Vedere ancheSee Also

Generazione SQLSQL Generation