Note 1: Gradle configuration and common add, delete, change, and query
[TOC]
1. Gradle Settings
1.1 enable mavenCentral
Root project build.gradle
repositories {
mavenCentral()
}
Copy the code
Add (project level) to build.gradle
Buildscript {ext.objectboxVersion = '2.9.1' dependencies {classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion" } }Copy the code
Add build.gradle to app (Module level)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // Only for Kotlin projects.
apply plugin: 'kotlin-kapt' // Only for Kotlin projects.
apply plugin: 'io.objectbox' // Apply last. after applying Android plugin
Copy the code
1.4 Adding a Dependency
dependencies {
implementation "io.objectbox:objectbox-java:$objectboxVersion"
implementation "io.objectbox:objectbox-android:$objectboxVersion"
}
Copy the code
1.5 Configuration Supports incremental comment processing
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ "objectbox.incremental" : "true" ]
}
}
}
}
Copy the code
1.6 Objectbox Usage Process
1.6.1 Define entity classes and then Build > Make Project
If Gradle is configured correctly, a file such as MyObjectBox will be generated under app\build\generated\ap_generated_sources\debug\out.
Json file app/objectbox-models/default.json will be automatically generated. Please add this file to version control and do not delete it. Do not manually modify the contents.
1.6.2 create BoxStore
After the BoxStore is initialized in the Application, you can use the BoxStore to add, delete, modify, and query the data table.
public class ObjectBox { private static BoxStore boxStore; public static void init(Context context) { boxStore = MyObjectBox.builder() .androidContext(context.getApplicationContext()) .build(); } public static BoxStore get() { return boxStore; }}Copy the code
2. Annotations related to entity classes
@Entity public class User { @Id public long id; public String name; If the field is private, there must be a standard getters method. private String name2; public String getName2() { return this.name; }}Copy the code
@Entity:
Annotated to class to represent a database table, the entity must also have a no-argument constructor.
@Id :
Annotated to a member attribute, representing an incremented ID, must be of type long (Java Kotlin: long; Dart: int). The @ID attribute cannot be private. By default, the ID attribute is unique and indexed. If you do not specify an ID when adding data to a table, the ObjectBox assigns the ID of the new object
@Index:
Annotations to member attributes, representing indexes, can improve performance when querying. @index currently does not support String[], byte[], float and double. When querying, use case-sensitive conditions if it is a string
StringIdEntity entity = box.query() .equal(StringIdEntity_.uid, uid, StringOrder.CASE_SENSITIVE) .build().findUnique()
Copy the code
@Transient
Annotation to a member attribute indicates that the attribute is not persisted in the table. Static properties in Java are also not persisted in tables.
@NameInDb(“username”)
Specifies the database field that corresponds to the corresponding member attribute in the table. Make it possible for member attribute names and database names to be different.
@Unique
A UniqueViolationException is thrown if the value of a field to be added to a table is the same as that of an existing table
try {
box.put(new User("Sam Flynn"));
} catch (UniqueViolationException e) {
// A User with that name already exists.
}
Copy the code
3. Add, delete, modify and check Objectbox data
3.1 increase the put
notesBox = ObjectBox.get().boxFor(Note.class); private void addNote() { ... Note note = new Note(); note.setText(noteText); note.setComment(comment); note.setDate(new Date()); notesBox.put(note); Log.d(App.TAG, "Inserted new note, ID: " + note.getId()); . }Copy the code
3.2 remove the remove
notesBox.remove(note); Log.d(App.TAG, "Deleted note, ID: " + note.getId()); // When a relational table is queried, the associated data will be found, but when a relational table is deleted, the associated data will not be directly deleted.Copy the code
3.3 change
Note. SetText ("This note has changed."); notesBox.put(note);Copy the code
3.4 check
Query<User> query = userBox.query().equal(User_.firstName, "Joe").build();
List<User> joes = query.find();
query.close();
Copy the code
Common search conditions:
Equal: the value is equal
Greater.
StartsWith: start with xx
3.4.1 Querying AND or Information using Multiple Criteria
// equal AND (less OR oneOf)
Query<User> query = box.query(
User_.firstName.equal("Joe")
.and(User_.age.less(12)
.or(User_.stamp.oneOf(new long[]{1012}))))
.order(User_.age)
.build();
Copy the code
3.4.2 Ordering Ordering
Flags can also be passed to order() to sort in descending order, case sensitive, or specifically to handle null values. For example, the results above are sorted in descending and case sensitive order
.order(User_.lastName, QueryBuilder.DESCENDING | QueryBuilder.CASE_SENSITIVE)
Copy the code
Rule 3.4.3 debugFlags
What query does the ObjectBox actually execute to see
// Set the LOG_QUERY_PARAMETERS debug flag BoxStore store = MyObjectBox.builder() .debugFlags(DebugFlags.LOG_QUERY_PARAMETERS) .build(); // Execute a query query.find(); Parameters for query #2: (firstName ==(I) "Joe" AND age < 12)Copy the code
3.4.4 Find Operation Query
// return all entities matching the query List<User> joes = query.find(); // return only the first result or null if none User joe = query.findFirst(); Return the only result or null if none, throw if more than one result, it will throw an exception. User joe = query.findUnique();Copy the code
3.4.5 Multiplexing Query and query parameters.
If you often run the same query, you should cache the Query object and reuse it. To make Query more reusable, you can even change the value of each condition or Query parameter you add after you build Query,
The related method setParameter
// build a query Query<User> query = userBox.query().equal(User_.firstName, "").build(); // change firstName parameter to "Joe", get results List<User> joes = query.setParameter(User_.firstName, "Joe").find(); . // change firstName parameter to "Jake", get results List<User> jakes = query.setParameter(User_.firstName, "Jake").find();Copy the code
3.4.6 Pagination, Limit, Offset, and Pagination
// offset by 10, limit to at most 5 results // Offset by 10, limit to at most 5 results List<User> joes = query.find(10, 5);Copy the code
3.4.7 Lazily loading Lazy loading Results
To avoid loading query results immediately, Query provides findLazy() and findLazyCached(), which return a LazyList of query results.
LazyList is a thread-safe, non-modifiable list that lazily reads entities only when they are accessed. Depending on which find method is called, the lazy list is cached. The cached lazy list stores previously accessed objects to avoid loading entities multiple times. Some features of lists are limited to caching lists (such as features that require the entire list)
3.4.8 Query Results Stream is returned as a stream
Only THE DART is supported
Query<User> query = userBox.query().build();
Stream<User stream = query.stream();
await stream.forEach((User user) => print(user));
query.close();
Copy the code
3.4.9 Querying only the Value of a Column. PropertyQuery
The array of property values returned does not have any particular order, even if you specified the order when you built the query.
String[] emails = userBox.query().build()
.property(User_.email)
.findStrings();
// or use .findString() to return just the first result
Copy the code
By default, no null value is returned. However, if an attribute is empty, you can specify a replacement value to return:
String[] emails = userBox.query().build()
.property(User_.email)
.nullValue("unknown")
.findStrings();
Copy the code
3.5.0 Querying Distinct and Unique Results Again
PropertyQuery pq = userBox.query().build().property(User_.firstName);
// returns ['joe'] because by default, the case of strings is ignored.
String[] names = pq.distinct().findStrings();
// returns ['Joe', 'joe', 'JOE']
String[] names = pq.distinct(StringOrder.CASE_SENSITIVE).findStrings();
// the query can be configured to throw there is more than one value
String[] names = pq.unique().findStrings();
Copy the code
3.5.1 Aggregating Values
Property queries (JavaDoc and Dart API documentation) also provide aggregate functions to directly calculate the minimum, maximum, average, sum, and count of all found values:
**min()/minDouble():** Finds the minimum value of the given attribute on all objects matching the query.
** Max ()/maxDouble() : ** Find the maximum value
**sum()/sumDouble() : ** evaluates the sum of all values. Note: The non-double version detects an overflow and throws an exception in this case.
** AVG () : ** Computes the average of all values (always double).
**count() : ** The number of results returned. This is faster than finding and getting the length of the result array. You can use this in combination with distinct() to count only the number of distinct values.
3.5.2 Links Add Query conditions for related entities (links)
After you create relationships between entities, you may want to add query criteria for attributes that only exist in related entities. In SQL, this can be done using joins. But since The ObjectBox is not an SQL database, we built something very similar: links. Links based on relationships
Suppose you have a Person that can be associated with multiple Address entities: a ToMany one-to-many relationship
@Entity
public class Person {
@Id long id;
String name;
ToMany<Address> addresses;
}
@Entity
public class Address {
@Id long id;
String street;
String zip;
}
Copy the code
To get a Person with a particular name who also lives on a particular street, we need to query the associated Address entity of the Person, using the link() method of the query builder to say that the Address relationship should be queried. Then add a condition to Address.
// get all Person objects named "Elmo"... QueryBuilder<Person> builder = personBox .query().equal(Person_.name, "Elmo"); / /... which have an address on "Sesame Street" builder.link(Person_.addresses).equal(Address_.street, "Sesame Street"); List<Person> elmosOnSesameStreet = builder.build().find();Copy the code
What if we want an Address list instead of a Person list?
// get all Address objects with street "Sesame Street"... QueryBuilder<Address> builder = addressBox.query() .equal(Address_.street, "Sesame Street"); / /... which are linked from a Person named "Elmo" builder.backlink(Person_.addresses).equal(Person_.name, "Elmo"); List<Address> sesameStreetsWithElmo = builder.build().find();Copy the code
3.5.3 Data in the Associated Query is Eager Loading of Relations
Only Java/Kotlin
By default, the association is lazy-loaded: the first time you access the ToOne or ToMany attribute, it performs a database lookup to retrieve its data. It will use a cached version of that data on each subsequent access.
List<Customer> customers = customerBox.query().build().find();
// Customer has a ToMany called orders.
// First access: this will cause a database lookup.
Order order = customers.get(0).orders.get(0);
Copy the code
Although the initial lookup is fast, you may want to prefetch the ToOne or ToMany values before returning the query results. Call QueryBuilder for this. Build the query using the eager method and pass the RelationInfo object associated with the ToOne and ToMany properties to prefetch:
List<Customer> customers = customerBox.query() .eager(Customer_.orders) // Customer has a ToMany called orders. .build() .find(); // First access: this will cause a database lookup. Order order = customers.get(0).orders.get(0);Copy the code
Only applicable to deep replication.
3.5.4 Querying Query filters
Query filters come into play when you are looking for objects that need to match complex conditions that cannot be fully represented by the QueryBuilder class. Filters are written in Java, so they can express any complexity. Needless to say, database conditions can be matched more efficiently than java-based filters. Therefore, you will get the best results when you use both together:
1. Use standard database criteria to narrow the results down to a reasonable number
2. Now, use the QueryFilter Java interface to filter these candidates to determine the final result
// Reduce object count to reasonable value.
songBox.query().equal(Song_.bandId, bandId)
// Filter is performed on candidate objects.
.filter((song) -> song.starCount * 2 > song.downloads);
Copy the code