CRUD - Leitura - Java SDK
Nesta página
- Ler operações
- Leia as características
- Os resultados não são cópias
- Os resultados são preguiçosos
- As referências são retidas
- Sobre os exemplos nesta página
- Ler do Realm
- Encontrar um objeto específico por chave primária
- Consultar todos os objetos de dado específico
- Filtrar consultas com base nas propriedades do objeto
- Classificar Resultados da Consulta
- Fazer query em um relacionamento
- Consultar um Relacionamento Inverso
- Dados agregados
Ler operações
Você pode ler os dados armazenados em Realm. O padrão de acesso a dados nos SDKs do Realm é localizar, filtrar e classificar objetos, nessa ordem. Para obter o melhor desempenho do Realm à medida que seu aplicativo cresce e suas queries se tornam mais complexas, crie os padrões de acesso a dados da sua aplicação em torno de uma sólida compreensão dascaracterísticas de leiturado Realm .
Leia as características
Quando você projeta os padrões de acesso a dados da sua aplicação em torno das três principais características de leituras a seguir no Realm, você pode ter certeza de que está lendo dados da forma mais eficiente possível.
Os resultados não são cópias
Os resultados de uma consulta não são cópias de seus dados: a modificação dos resultados de uma consulta modificará diretamente os dados no disco. Esse mapeamento de memória também significa que os resultados são ativos: ou seja, eles sempre refletem o estado atual no disco.
Os resultados são preguiçosos
O Realm adia a execução de uma query até que você acesse os resultados. Você pode encadear várias operações de filtro e classificação sem exigir trabalho extra para processar o estado intermediário.
As referências são retidas
Uma vantagem do modelo de objeto de Realm é que ele retém automaticamente todos os relacionamentos de um objeto como referências diretas, portanto você pode percorrer o grafo de relacionamentos diretamente por meio dos resultados de uma consulta.
Uma referência direta, ou ponteiro, permite que você acesse diretamente as propriedades de um objeto relacionado por meio da referência.
Outros bancos de dados geralmente copiam objetos do armazenamento do banco de dados para a memória do aplicativo quando você precisa trabalhar com eles diretamente. Como os objetos do aplicativo contêm referências diretas, você tem uma opção: copiar o objeto referido por cada referência direta para fora do banco de dados, caso seja necessário, ou apenas copiar a chave estrangeira de cada objeto e consultar o objeto com essa chave, se ele for acessado. Se você optar por copiar os objetos referenciados para a memória do aplicativo, poderá usar muitos recursos para objetos que nunca são acessados, mas se optar por copiar apenas a chave estrangeira, as pesquisas de objetos referenciados poderão causar lentidão no aplicativo.
O Realm contorna tudo isso com objetos ativos de cópia zero. Os acessadores de objeto de realm apontam diretamente para o armazenamento de banco de dados usando o mapeamento de memória, portanto não há distinção entre os objetos no Realm e os resultados da consulta na memória do aplicativo. Por isso você pode percorrer referências diretas em um domínio inteiro a partir de qualquer resultado de consulta.
Sobre os exemplos nesta página
Os exemplos nesta página usam o Modelo de dados Realm de um aplicativo de gerenciamento de projeto que tem dois Tipo de objeto de Realm: Project
e Task
. Um Project
tem zero ou mais Tasks
.
Consulte o esquema para estas duas classes, Project
e Task
, abaixo:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class ProjectTask extends RealmObject { public ObjectId _id; public String name; public String assignee; public int progressMinutes; public boolean isComplete; public int priority; public String _partition; }
import org.bson.types.ObjectId; import io.realm.RealmList; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class Project extends RealmObject { public ObjectId _id; public String name; public RealmList<ProjectTask> tasks = new RealmList<>(); }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class ProjectTask( var _id: ObjectId = ObjectId(), var name: String = "", var assignee: String? = null, var progressMinutes: Int = 0, var isComplete: Boolean = false, var priority: Int = 0, var _partition: String = "" ): RealmObject()
import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class Project( var _id: ObjectId = ObjectId(), var name: String = "", var tasks: RealmList<ProjectTask> = RealmList(), ): RealmObject()
Ler do Realm
Uma leitura de um reino geralmente consiste nas seguintes etapas:
Obtenha todos os objetos de um determinado tipo do realm.
Opcionalmente, filtre os resultados usando o mecanismo de consulta.
Opcionalmente, classifique os resultados.
Todas as operações de consulta, filtro e classificação retornam uma coleção de resultados. As coleções de resultados estão ativas, o que significa que elas sempre contêm os resultados mais recentes da query associada.
Importante
Leituras e gravações síncronas na thread da interface do usuário
Por padrão, você só pode ler ou escrever em um realm no thread da UI do aplicativo usando transações assíncronas. Ou seja, você só pode usar métodos Realm
cujo nome termina com a palavra Async
no thread principal do seu aplicativo Android, a menos que você permita explicitamente o uso de métodos síncronos.
Essa restrição existe para o benefício dos usuários do aplicativo: executar operações de leitura e escrita no thread da interface do usuário pode levar a interações de interface do usuário não responsivas ou lentas, portanto, geralmente é melhor lidar com essas operações de forma assíncrona ou em um thread de fundo. No entanto, se o seu aplicativo exigir o uso de leituras ou gravações síncronas de realm no thread da interface do usuário, você poderá permitir explicitamente o uso de métodos síncronos com as seguintes opções SyncConfiguration
:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); } });
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread.") } })
Encontrar um objeto específico por chave primária
Para encontrar um objeto com um valor de chave primária específico, abra um Realm e consulte o campo de chave primária para o valor de chave primária desejado usando o método RealmQuery.equalTo() método:
ProjectTask task = realm.where(ProjectTask.class).equalTo("_id", PRIMARY_KEY_VALUE.get()).findFirst(); Log.v("EXAMPLE", "Fetched object by primary key: " + task);
val task = realm.where(ProjectTask::class.java) .equalTo("_id", ObjectId.get()).findFirst() Log.v("EXAMPLE", "Fetched object by primary key: $task")
Consultar todos os objetos de dado específico
O primeiro passo de qualquer leitura é obter todos os objetos de um determinado tipo em um Realm. Com essa coleção de resultados, você pode operar em todas as instâncias em um tipo ou filtro e classificar para refinar os resultados.
Para acessar todas as instâncias de ProjectTask
e Project
, use o método onde() para especificar uma classe:
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); RealmQuery<Project> projectsQuery = realm.where(Project.class);
val tasksQuery = realm.where(ProjectTask::class.java) val projectsQuery = realm.where(Project::class.java)
Filtrar consultas com base nas propriedades do objeto
Um filtro seleciona um subconjunto de resultados com base nos valores de uma ou mais propriedades do objeto. O Realm oferece um mecanismo de query completo que você pode usar para definir filtros. O caso de uso mais comum é localizar objetos onde uma determinada propriedade corresponde a um determinado valor. Além disso, você pode comparar strings, agregar coleções de números e usar operadores lógicos para criar query complexas.
No exemplo a seguir, usamos operadores de comparação do mecanismo de consulta para:
Encontre tarefas de alta prioridade comparando o valor da propriedade
priority
com um número limite, acima do qual a prioridade pode ser considerada alta.Encontre tarefas recém-iniciadas ou de curta duração verificando se a propriedade
progressMinutes
está dentro de um determinado intervalo.Encontre tarefas não atribuídas encontrando tarefas onde a propriedade
assignee
é igual a nula.Encontre tarefas atribuídas a membros específicos da equipe Ali ou Jamie verificando se a propriedade
assignee
está em uma lista de nomes.
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); Log.i("EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan("priority", 5).count()); Log.i("EXAMPLE", "Just-started or short tasks: " + tasksQuery.between("progressMinutes", 1, 10).count()); Log.i("EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count()); Log.i("EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.in("assignee", new String[]{"Ali", "Jamie"}).count());
val tasksQuery = realm.where(ProjectTask::class.java) Log.i( "EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan( "priority", 5 ).count() ) Log.i( "EXAMPLE", "Just-started or short tasks: " + tasksQuery.between( "progressMinutes", 1, 10 ).count() ) Log.i( "EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count() ) Log.i( "EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.`in`( "assignee", arrayOf( "Ali", "Jamie" ) ).count() )
Classificar Resultados da Consulta
Uma operação de classificação permite configurar a ordem na qual o Realm retorna objetos consultados. A classificação pode ser feita com base em uma ou mais propriedades dos objetos na collection de resultados.
O Realm garante apenas uma ordem consistente de resultados quando os resultados são classificados.
O código a seguir classifica os projetos por nome em ordem alfabética inversa (ou seja, "ordem decrescente").
RealmQuery<Project> projectsQuery = realm.where(Project.class); RealmResults<Project> results = projectsQuery.sort("name", Sort.DESCENDING).findAll();
val projectsQuery = realm.where(Project::class.java) val results = projectsQuery.sort("name", Sort.DESCENDING).findAll()
Fazer query em um relacionamento
Considere o seguinte relacionamento entre as classes Human
e Cat
. Este acordo permite que cada ser humano tenha um único cão:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
Para consultar esse relacionamento, use a notação de ponto em um query para acessar qualquer propriedade do objeto vinculado :
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); realm.executeTransaction(transactionRealm -> { Human owner = transactionRealm.where(Human.class).equalTo("cat.name", "bucky").findFirst(); Cat cat = owner.getCat(); Log.v("EXAMPLE", "Queried for humans with cats named 'bucky'. Found " + owner.getName() + ", who owns " + cat.getName()); }); realm.close(); } });
Considere o seguinte relacionamento entre as classes Person
e Dog
. Esse acordo permite que cada pessoa tenha um único cachorro:
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
Para consultar esse relacionamento, use a notação de ponto em um query para acessar qualquer propriedade do objeto vinculado :
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val owner = transactionRealm.where<Person>().equalTo("dog.name", "henry").findFirst() val dog = owner?.dog Log.v("EXAMPLE", "Queried for people with dogs named 'henry'. Found $owner, owner of $dog") } realm.close() } })
Consultar um Relacionamento Inverso
Considere o seguinte relacionamento entre as classes Cat
e Human
. Neste exemplo, todos os gatos estão vinculados a seu ser humano (ou a vários humanos, se vários objetos humanos se referirem ao mesmo cão). O Realm calcula os proprietários de cada animal para você com base no nome do campo fornecido à anotação @LinkingObjects
:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
Para consultar esse relacionamento, use a notação de ponto em um query para acessar qualquer propriedade do objeto vinculado :
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); realm.executeTransaction(transactionRealm -> { Cat cat = transactionRealm.where(Cat.class) .equalTo("owner.name", "steven").findFirst(); Human owner = cat.getOwner().first(); Log.v("EXAMPLE", "Queried for cats with owners named 'steven'. Found " + cat.getName() + ", owned by " + owner.getName()); }); realm.close(); } });
Considere o seguinte relacionamento entre as classes Dog
e Person
. Neste exemplo, todos os cães estão vinculados ao proprietário (ou a vários proprietários, se vários objetos de pessoa se referirem ao mesmo cão). O Realm calcula os proprietários de cada cão para você com base no nome do campo fornecido à anotação @LinkingObjects
:
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
Para consultar esse relacionamento, use a notação de ponto em um query para acessar qualquer propriedade do objeto vinculado :
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val dog = transactionRealm.where<Dog>() .equalTo("owner.name", "dwayne").findFirst() val owner = dog?.owner?.first() Log.v("EXAMPLE", "Queried for dogs with owners named 'dwayne'. Found $dog, owned by $owner") } realm.close() } })
Dados agregados
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */ Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"));
val tasksQuery = realm.where(ProjectTask::class.java) /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"))