(安卓)ObjectBox數(shù)據(jù)庫筆記
[TOC]
1.Gradle設(shè)置
1.1 啟用mavenCentral
根工程里的build.gradle
repositories {
mavenCentral()
}
1.2 根build.gradle文件里添加 (project level)
buildscript {
ext.objectboxVersion = '2.9.1'
dependencies {
classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
}
}
1.3 app 里的 build.gradle 添加 (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
1.4 添加依賴
dependencies {
implementation "io.objectbox:objectbox-java:$objectboxVersion"
implementation "io.objectbox:objectbox-android:$objectboxVersion"
}
1.5 配置 支持增量注釋處理
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ "objectbox.incremental" : "true" ]
}
}
}
}
1.6 Objectbox使用流程
1.6.1 定義實體類,然后 Build > Make Project
如果gradle配置正確,將會在app\build\generated\ap_generated_sources\debug\out下生成相應(yīng)的文件,例如MyObjectBox等。
同時,會自動生成 app/objectbox-models/default.json文件,請把這一個文件加入版本控制,不要刪除。不要手動修改里面的內(nèi)容。
1.6.2 創(chuàng)建 BoxStore
在Application里初始化BoxStore后,可以使用BoxStore對數(shù)據(jù)表進(jìn)行增刪改查操作。
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; }
}
2.實體類相關(guān)注解
@Entity
public class User {
@Id
public long id;
public String name;
//如果字段是私有的,則必須有一個標(biāo)準(zhǔn)的getters方法。
private String name2;
public String getName2() {
return this.name;
}
}
@Entity:
注解到class上,代表是一個數(shù)據(jù)庫表,實體也必須有一個無參數(shù)的構(gòu)造函數(shù)。
@Id :
注解到成員屬性上,代表是自增id,必須是long型(java kotlin 里是long型 dart里是int型),@Id 注解的成員屬性不能是私有的。默認(rèn)情況下,ID屬性是惟一的,并且有索引。向表里新增數(shù)據(jù)時,如果不指定id,則新對象的id由ObjectBox分配
@Index:
注解到成員屬性上,代表索引,可以在查詢時,提高性能。@Index目前不支持String[], byte[], float和double。查詢時,如果是字符串,則使用區(qū)分大小寫的條件
StringIdEntity entity = box.query() .equal(StringIdEntity_.uid, uid, StringOrder.CASE_SENSITIVE) .build().findUnique()
@Transient
注解到成員屬性上,代表這一個屬性不被持久化到表里。java里的靜態(tài)屬性也不會持久化到表里。
@NameInDb("username")
指定相應(yīng)成員屬性在數(shù)據(jù)表里對應(yīng)的數(shù)據(jù)庫字段。使成員屬性名和數(shù)據(jù)庫名可以不一樣。
@Unique
唯一約束,如果put時,將要向表里增加的記錄和表里已經(jīng)有一個表記錄的字段值相同,則會拋異常UniqueViolationException
try {
box.put(new User("Sam Flynn"));
} catch (UniqueViolationException e) {
// A User with that name already exists.
}
3.Objectbox數(shù)據(jù)的增刪改查
3.1 增 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());
...
}
3.2刪除 remove
notesBox.remove(note);
Log.d(App.TAG, "Deleted note, ID: " + note.getId());
//關(guān)系表查詢時,會查出關(guān)聯(lián)的數(shù)據(jù),但是刪除時,關(guān)聯(lián)的數(shù)據(jù)并不會直接刪除。
3.3改
直接使用put ,但是id值不能為null
note.setText("This note has changed.");
notesBox.put(note);
3.4查
Query<User> query = userBox.query().equal(User_.firstName, "Joe").build();
List<User> joes = query.find();
query.close();
常用的查詢條件:
equal:值相等
greater:大于
startsWith:以xx為開始
3.4.1 多條件查詢 and or
// 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();
3.4.2 Ordering 排序
還可以將標(biāo)志傳遞給order()以按降序排序、區(qū)分大小寫排序或特別處理空值。例如,要對上面的結(jié)果進(jìn)行降序和區(qū)分大小寫的排序
.order(User_.lastName, QueryBuilder.DESCENDING | QueryBuilder.CASE_SENSITIVE)
3.4.3 debugFlags
要查看ObjectBox實際執(zhí)行了什么查詢語句
// 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)
3.4.4 find操作查詢
// 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 如果有多個結(jié)果,它會拋出一個異常。
User joe = query.findUnique();
3.4.5復(fù)用query和查詢參數(shù)。
如果您經(jīng)常運行相同的查詢,您應(yīng)該緩存query對象并重用它。要使Query更具可重用性,您甚至可以在構(gòu)建Query之后更改所添加的每個條件的值或查詢參數(shù),
相關(guān)方法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();
3.4.6 分頁相關(guān),Limit, Offset, and Pagination
// offset by 10, limit to at most 5 results
//下標(biāo)從0開始,包含開始下標(biāo)。
List<User> joes = query.find(10, 5);
3.4.7 延遲加載 Lazy loading results
為了避免立即加載查詢結(jié)果,query提供了findLazy()和findLazyCached(),它們返回查詢結(jié)果的LazyList。
LazyList是一個線程安全的、不可修改的列表,它只在實體被訪問時才惰性地讀取實體。根據(jù)調(diào)用的find方法,懶列表是否會被緩存。緩存的惰性列表存儲以前訪問過的對象,以避免多次加載實體。列表的一些特性僅限于緩存列表(例如需要整個列表的特性)
3.4.8 查詢結(jié)果作為一個流返回 Query results stream
暫只支持dart
Query<User> query = userBox.query().build();
Stream<User stream = query.stream();
await stream.forEach((User user) => print(user));
query.close();
3.4.9只查詢某一列的值。PropertyQuery
返回的屬性值數(shù)組沒有任何特定的順序,即使您在構(gòu)建查詢時指定了順序。
String[] emails = userBox.query().build()
.property(User_.email)
.findStrings();
// or use .findString() to return just the first result
默認(rèn)情況下,不返回空值。但是,如果一個屬性為空,你可以指定一個替換值來返回:
String[] emails = userBox.query().build()
.property(User_.email)
.nullValue("unknown")
.findStrings();
3.5.0 去重查詢 Distinct and unique results
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();
3.5.1 聚合值 Aggregating values
屬性查詢(JavaDoc和Dart API文檔)還提供了聚合函數(shù)來直接計算所有發(fā)現(xiàn)值的最小值、最大值、平均值、總和和計數(shù):
min() / minDouble():在匹配查詢的所有對象上查找給定屬性的最小值。
max() / maxDouble():找到最大值
sum() / sumDouble():計算所有值的和。注意:非雙精度版本檢測溢出并在這種情況下拋出異常。
avg():計算所有值的平均值(總是雙精度)。
count():返回結(jié)果的數(shù)量。這比查找和獲取結(jié)果數(shù)組的長度要快??梢耘cdistinct()組合使用,只計算不同值的數(shù)量。
3.5.2 關(guān)聯(lián)表查詢 links Add query conditions for related entities (links)
在創(chuàng)建實體之間的關(guān)系之后,您可能希望為只存在于相關(guān)實體中的屬性添加查詢條件。在SQL中,這可以使用join來解決。但由于ObjectBox不是一個SQL數(shù)據(jù)庫,我們構(gòu)建了一些非常類似的東西:links。鏈接基于關(guān)系
假設(shè)有一個Person可以與多個Address實體相關(guān)聯(lián): ToMany 一對多關(guān)系
@Entity
public class Person {
@Id long id;
String name;
ToMany<Address> addresses;
}
@Entity
public class Address {
@Id long id;
String street;
String zip;
}
獲取具有特定名稱且也居住在特定街道上的Person,我們需要查詢Person的關(guān)聯(lián)Address實體,為此,使用查詢構(gòu)建器的link()方法來說明應(yīng)該查詢地址關(guān)系。然后為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();
如果我們想要一個Address列表而不是Person列表,該怎么辦?
// 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();
3.5.3 立即預(yù)取關(guān)聯(lián)查詢里的所有數(shù)據(jù) Eager Loading of Relations
Only Java/Kotlin
默認(rèn)情況下,關(guān)聯(lián)是惰性加載的:當(dāng)您第一次訪問ToOne或ToMany屬性時,它將執(zhí)行數(shù)據(jù)庫查找以獲取其數(shù)據(jù)。在每次后續(xù)訪問時,它將使用該數(shù)據(jù)的緩存版本。
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);
雖然初始查找速度很快,但您可能希望在返回查詢結(jié)果之前預(yù)取ToOne或ToMany值。為此調(diào)用QueryBuilder。在構(gòu)建查詢時使用eager方法,并傳遞與ToOne和ToMany屬性關(guān)聯(lián)的RelationInfo對象來預(yù)取:
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);
只適用于深復(fù)制。
3.5.4 查詢過濾器 Query filters
當(dāng)您尋找需要匹配復(fù)雜條件的對象時(這些條件不能用QueryBuilder類完全表示),查詢過濾器就發(fā)揮作用了。過濾器是用Java編寫的,因此可以表達(dá)任何復(fù)雜性。不用說,與基于java的過濾器相比,可以更有效地匹配數(shù)據(jù)庫條件。因此,當(dāng)你將兩者一起使用時,你將得到最好的結(jié)果:
1.使用標(biāo)準(zhǔn)數(shù)據(jù)庫條件將結(jié)果縮小到合理的數(shù)量
2.現(xiàn)在,使用QueryFilter Java接口對這些候選者進(jìn)行篩選,以確定最終結(jié)果
// 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);