Questo documento è incentrato sull'uso JDO (Java Data Objects) il framework di persistenza per le query App Engine Datastore. Per informazioni più generali informazioni sulle query, consulta le Query Datastore .
Una query recupera entità da Datastore che soddisfano un insieme specificato di condizioni. La query opera su entità di una data kind; può specificare filtri sulle entità valori di proprietà, chiavi e predecessori e può restituire zero più entità come risultati. Una query può anche specificare ordinare per sequenziare i risultati in base ai valori delle proprietà. I risultati includono tutte le entità che hanno almeno un valore (eventualmente nullo) per ogni proprietà denominata nei filtri e negli ordini di ordinamento e i cui valori delle proprietà soddisfano tutti i criteri di filtro specificati. La query può restituire intere entità, entità previste, o semplicemente entità chiavi.
Una query tipica include quanto segue:
- Un tipo di entità a cui si applica la query
- Zero o più filtri basati su valori, chiavi e antenati delle proprietà delle entità
- Zero o più ordinare per sequenziare i risultati
Nota: per risparmiare memoria e migliorare una query, quando possibile, deve specificare un limite al numero vengono restituiti i risultati.
Nota: Il meccanismo di query basato su indice supporta un'ampia gamma di query ed è adatto a per la maggior parte delle applicazioni. Tuttavia, non supporta alcuni tipi di query comuni in altre tecnologie di database: in particolare, join e query aggregate non sono supportate nel motore di query di Datastore. Consulta la pagina Query Datastore per informazioni sui limiti delle query Datastore.
Query con JDOQL
JDO include un linguaggio di query per il recupero di oggetti che soddisfano un insieme di criteri. Questo linguaggio, chiamato JDOQL, fa riferimento direttamente alle classi e ai campi di dati JDO e include il controllo del tipo per i parametri e i risultati delle query. JDOQL è simile a SQL, ma è più appropriato per i database orientati agli oggetti come Datastore di App Engine. (App Engine di implementazione dell'API JDO non supporta direttamente le query SQL.)
Il JDO
Query
supporta diversi stili di chiamata: puoi specificare una query completa in
stringa, utilizzando la sintassi della stringa JDOQL, oppure puoi specificare alcune o tutte le parti
richiamando metodi sull'oggetto Query
. L'esempio seguente mostra lo stile di chiamata del metodo, con un filtro e un ordine di ordinamento, utilizzando la sostituzione del parametro per il valore utilizzato nel filtro. L'argomento
passati all'oggetto Query
execute()
vengono sostituiti nella query nell'ordine specificato:
import java.util.List; import javax.jdo.Query; // ... Query q = pm.newQuery(Person.class); q.setFilter("lastName == lastNameParam"); q.setOrdering("height desc"); q.declareParameters("String lastNameParam"); try { List<Person> results = (List<Person>) q.execute("Smith"); if (!results.isEmpty()) { for (Person p : results) { // Process result p } } else { // Handle "no results" case } } finally { q.closeAll(); }
Ecco la stessa query che utilizza la sintassi di stringa:
Query q = pm.newQuery("select from Person " + "where lastName == lastNameParam " + "parameters String lastNameParam " + "order by height desc"); List<Person> results = (List<Person>) q.execute("Smith");
Puoi combinare questi stili di definizione della query. Ad esempio:
Query q = pm.newQuery(Person.class, "lastName == lastNameParam order by height desc"); q.declareParameters("String lastNameParam"); List<Person> results = (List<Person>) q.execute("Smith");
Puoi riutilizzare una singola istanza Query
con valori diversi sostituiti per i parametri chiamando il metodo execute()
più volte. Ogni chiamata esegue la query e restituisce i risultati come
.
La sintassi della stringa JDOQL supporta la specifica letterale di stringa e numerica
valori; tutti gli altri tipi di valore devono usare la sostituzione dei parametri. I valori letterali all'interno della stringa di query possono essere racchiusi tra virgolette singole ('
) o doppie ("
). Ecco un esempio in cui viene utilizzata una stringa
letterale:
Query q = pm.newQuery(Person.class, "lastName == 'Smith' order by height desc");
Filtri
Un filtro proprietà specifica
- Un nome di proprietà
- Un operatore di confronto
- Un valore della proprietà
Query q = pm.newQuery(Person.class); q.setFilter("height <= maxHeight");
Il valore della proprietà deve essere fornito dall'applicazione; non può fare riferimento a o essere calcolato in termini di altre proprietà. Un'entità soddisfa il filtro se ha una proprietà del nome specificato il cui valore è confrontato con quello specificato il filtro nel modo descritto dall'operatore di confronto.
L'operatore di confronto può essere uno dei seguenti:
Operatore | Significato |
---|---|
== |
Uguale a |
< |
Minore di |
<= |
Minore o uguale a |
> |
Maggiore di |
>= |
Maggiore o uguale a |
!= |
Diverso da |
Come descritto nel
Query
una singola query non può utilizzare filtri di disuguaglianza
(<
, <=
,
>
, >=
,
!=
) in più di una proprietà. Sono consentiti più
filtri di disuguaglianza nella stessa proprietà, ad esempio query su un intervallo di valori. contains()
filtro, corrispondente a
I filtri IN
in SQL sono supportati con la seguente sintassi:
// Query for all persons with lastName equal to Smith or Jones Query q = pm.newQuery(Person.class, ":p.contains(lastName)"); q.execute(Arrays.asList("Smith", "Jones"));
L'operatore di diseguaglianza (!=
)
esegue in realtà due query: una in cui tutti gli altri filtri rimangono invariati e il
filtro di diseguaglianza viene sostituito con un
filtro minore di (<
)
e un'altra in cui viene sostituito con un
filtro maggiore di (>
). I risultati vengono poi uniti in ordine. Una query può avere al massimo
non uguale
e una query con uno non può avere altri filtri di disuguaglianza.
L'operatore contains()
esegue anche
query: una per ogni elemento nell'elenco specificato, con tutti gli altri filtri
non modificato e il filtro contains()
è stato sostituito con
uguaglianza (==
)
filtro. I risultati vengono uniti in base agli elementi nell'elenco. Se una query contiene più di un filtro contains()
, viene eseguita come più query, una per ogni possibile combinazione di valori negli elenchi contains()
.
Una singola query contenente
operatori di non uguale (!=
)
o contains()
è limitata a un massimo di 30 sottoquery.
Per ulteriori informazioni su come le query !=
e contains()
vengono tradotte in più query in un framework JDO/JPA, consulta l'articolo
Query con filtri != e IN.
Nella sintassi di stringa JDOQL, puoi separare più filtri con gli operatori &&
("e" logico) e ||
("o" logico):
q.setFilter("lastName == 'Smith' && height < maxHeight");
La negazione (logica "not") non è supportata. Tieni inoltre presente che
L'operatore ||
può essere utilizzato solo quando i filtri separa tutti
che hanno lo stesso nome della proprietà, ovvero quando possono essere combinati in un
filtro contains()
):
// Legal: all filters separated by || are on the same property Query q = pm.newQuery(Person.class, "(lastName == 'Smith' || lastName == 'Jones')" + " && firstName == 'Harold'"); // Not legal: filters separated by || are on different properties Query q = pm.newQuery(Person.class, "lastName == 'Smith' || firstName == 'Harold'");
Ordina
Un ordinamento di query specifica
- Un nome di proprietà
- Una direzione di ordinamento (crescente o decrescente)
Ad esempio:
Ad esempio:
// Order alphabetically by last name: Query q = pm.newQuery(Person.class); q.setOrdering("lastName asc"); // Order by height, tallest to shortest: Query q = pm.newQuery(Person.class); q.setOrdering("height desc");
Se una query include più ordinamenti, questi vengono applicati nella sequenza specificato. L'esempio seguente ordina prima per cognome in ordine crescente e poi per altezza in ordine decrescente:
Query q = pm.newQuery(Person.class); q.setOrdering("lastName asc, height desc");
Se non viene specificato alcun ordinamento, i risultati vengono restituiti nell'ordine in cui recuperate da Datastore.
Nota: per via del modo Datastore esegue le query, se una query specifica filtri di disuguaglianza su una proprietà e ordina le altre, la proprietà utilizzata nella I filtri di disuguaglianze devono essere ordinati prima delle altre proprietà.
Intervalli
Una query può specificare un intervallo di risultati da restituire all'applicazione. L'intervallo indica quali risultati nel set di risultati completo devono essere il primo e l'ultimo restituiti. I risultati sono identificati da indici numerici,
con 0
che indica il primo risultato dell'insieme. Ad esempio, un intervallo
di 5,
10
restituisce il 6° e il 10° risultato:
q.setRange(5, 10);
Nota: l'uso di intervalli può influire sulle prestazioni,
poiché Datastore deve recuperare e poi ignorare tutti i risultati che precedono
dall'offset iniziale. Ad esempio, una query con un intervallo di 5,
10
recupera dieci risultati da Datastore, ignora i primi
cinque e restituisce i cinque rimanenti all'applicazione.
Query basate su chiavi
Le chiavi di entità possono essere oggetto di un filtro di query o di un ordinamento. Datastore considera il valore della chiave completo per queste query, incluso il percorso dell'antenato dell'entità, il tipo e la stringa del nome della chiave assegnata dall'applicazione o l'ID numerico assegnato dal sistema. Poiché la chiave è univoca in tutte le entità in le query chiave semplificano il recupero di entità di un determinato tipo ad esempio per un dump dei contenuti di Datastore. A differenza degli intervalli JDOQL, questa operazione funziona in modo efficiente per qualsiasi numero di entità.
Quando si esegue il confronto per verificare l'ineguaglianza, le chiavi vengono ordinate in base ai seguenti criteri:
- Percorso predecessore
- Tipo di entità
- Identificatore (nome della chiave o ID numerico)
Gli elementi del percorso dell'antenato vengono confrontati in modo simile: per tipo (stringa), poi per nome della chiave o ID numerico. I tipi e i nomi delle chiavi sono stringhe e sono ordinati in base al valore in byte; gli ID numerici sono numeri interi e sono ordinati in ordine numerico. Se le entità con lo stesso elemento principale e lo stesso tipo utilizzano una combinazione di stringhe di nomi di chiavi e ID numerici, quelle con ID numerici precedono quelle con nomi di chiavi.
In JDO, fai riferimento alla chiave di entità nella query utilizzando il campo della chiave primaria
dell'oggetto. Per utilizzare una chiave come filtro di query, specifica il tipo di parametro
Key
alla
declareParameters()
. Quanto segue trova tutte le entità Person
con un determinato
il tuo cibo preferito, ipotizzando
relazione one-to-one senza proprietario
tra Person
e Food
:
Food chocolate = /*...*/; Query q = pm.newQuery(Person.class); q.setFilter("favoriteFood == favoriteFoodParam"); q.declareParameters(Key.class.getName() + " favoriteFoodParam"); List<Person> chocolateLovers = (List<Person>) q.execute(chocolate.getKey());
Una query basata solo su chiavi restituisce solo le chiavi delle entità di risultato anziché le entità stesse, con una latenza e un costo inferiori rispetto al recupero di entità intere:
Query q = pm.newQuery("select id from " + Person.class.getName()); List<String> ids = (List<String>) q.execute();
Spesso è più economico eseguire prima una query solo per le chiavi e poi recuperare un sottoinsieme di entità dai risultati, anziché eseguire una query generale che potrebbe recuperare più entità di quelle di cui hai bisogno.
Estensioni
Un'estensione JDO rappresenta ogni oggetto nel Datastore di una determinata classe. Per crearlo, passa la classe desiderata al riquadro Persistenza
Del gestore
getExtent()
. La
Extent
estende l'interfaccia
Iterable
per accedere ai risultati, recuperandoli in batch secondo le necessità. Quando
hai finito di accedere ai risultati, chiami
closeAll()
.
L'esempio seguente viene ripetuto per ogni oggetto Person
nella
Datastore:
import java.util.Iterator; import javax.jdo.Extent; // ... Extent<Person> extent = pm.getExtent(Person.class, false); for (Person p : extent) { // ... } extent.closeAll();
Eliminazione di entità in base alla query
Se stai inviando una query con l'obiettivo di eliminare tutte le entità corrisponde al filtro di query, puoi risparmiare un po' di codice utilizzando la codifica "elimina per query" funzionalità. Il seguente comando elimina tutte le persone di altezza superiore a una determinata:
Query q = pm.newQuery(Person.class); q.setFilter("height > maxHeightParam"); q.declareParameters("int maxHeightParam"); q.deletePersistentAll(maxHeight);
Noterai che l'unica differenza è che chiamiamo
q.deletePersistentAll()
instead of
q.execute()
.
Tutte le regole e le restrizioni descritte in precedenza per filtri, ordinamento e
alle query, indipendentemente dal fatto che tu stia selezionando o eliminando il set di risultati.
Tieni presente, però, che, come se avessi eliminato queste Person
entità con
pm.deletePersistent()
,
verranno eliminati anche tutti gli elementi figli dipendenti delle entità eliminate dalla query. Per ulteriori informazioni sui figli a carico, consulta la pagina
Relazioni di entità in JDO.
Cursori di query
In JDO, puoi utilizzare un'estensione e la classe JDOCursorHelper
per utilizzare i cursori con le query JDO. I cursori funzionano quando vengono recuperati i risultati come elenco o
utilizzando un iteratore. Per ottenere un cursore, passa l'elenco dei risultati o l'iteratore al metodo statico JDOCursorHelper.getCursor()
:
import java.util.HashMap; import java.util.List; import java.util.Map; import javax.jdo.Query; import com.google.appengine.api.datastore.Cursor; import org.datanucleus.store.appengine.query.JDOCursorHelper; Query q = pm.newQuery(Person.class); q.setRange(0, 20); List<Person> results = (List<Person>) q.execute(); // Use the first 20 results Cursor cursor = JDOCursorHelper.getCursor(results); String cursorString = cursor.toWebSafeString(); // Store the cursorString // ... // Query q = the same query that produced the cursor // String cursorString = the string from storage Cursor cursor = Cursor.fromWebSafeString(cursorString); Map<String, Object> extensionMap = new HashMap<String, Object>(); extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor); q.setExtensions(extensionMap); q.setRange(0, 20); List<Person> results = (List<Person>) q.execute(); // Use the next 20 results
Per ulteriori informazioni sui cursori di query, consulta la pagina Query Datastore.
Criterio di lettura del datastore e scadenza chiamata
Puoi impostare il criterio di lettura (coerenza forte o coerenza eventuale) e la scadenza della chiamata di Datastore per tutte le chiamate effettuate da un'istanza PersistenceManager
utilizzando la configurazione. Puoi anche eseguire l'override di queste opzioni per un singolo oggetto Query
. Tieni presente che
ma che non c'è modo di sostituire la configurazione per queste opzioni
quando recuperi le entità per chiave.)
Quando viene selezionata la coerenza finale per una query Datastore, anche agli indici utilizzati dalla query per raccogliere i risultati viene eseguito l'accesso con coerenza finale. A volte le query restituiscono entità che non corrispondono ai criteri di query, anche se questo accade anche con un criterio di lettura fortemente coerente. Se la query utilizza un filtro dei predecessori, puoi utilizzare transazioni per garantire un insieme di risultati coerente.)
Per ignorare il criterio di lettura per una singola query, chiama il relativo metodo
addExtension()
:
Query q = pm.newQuery(Person.class); q.addExtension("datanucleus.appengine.datastoreReadConsistency", "EVENTUAL");
I valori possibili sono "EVENTUAL"
e "STRONG"
; il valore predefinito è "STRONG"
, se non diversamente specificato nel file di configurazione jdoconfig.xml
.
Per sostituire la scadenza della chiamata di Datastore per una singola query, richiama la relativa
setDatastoreReadTimeoutMillis()
:
q.setDatastoreReadTimeoutMillis(3000);
Il valore è un intervallo di tempo espresso in millisecondi.