安卓-ObjectBox数据库笔记1:gradle配置和常用增删改查

(安卓)ObjectBox数据库笔记

[TOC]

1.Gradle设置

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下生成相应的文件,例如MyObjectBox等。

同时,会自动生成 app/objectbox-models/default.json文件,请把这一个文件加入版本控制,不要删除。不要手动修改里面的内容。

1.6.2 创建 BoxStore

在Application里初始化BoxStore后,可以使用BoxStore对数据表进行增删改查操作。

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.实体类相关注解

@Entity
public class User {
    @Id 
    public long id;
    public String name;
    //如果字段是私有的,则必须有一个标准的getters方法。
     private String name2;
     public String getName2() {
        return this.name;
    }

}
@Entity

注解到class上,代表是一个数据库表,实体也必须有一个无参数的构造函数

@Id :

注解到成员属性上,代表是自增id,必须是long型(java kotlin 里是long型 dart里是int型),@Id 注解的成员属性不能是私有的。默认情况下,ID属性是惟一的,并且有索引。向表里新增数据时,如果不指定id,则新对象的id由ObjectBox分配

@Index

注解到成员属性上,代表索引,可以在查询时,提高性能。@Index目前不支持String[], byte[], float和double。查询时,如果是字符串,则使用区分大小写的条件

StringIdEntity entity = box.query() .equal(StringIdEntity_.uid, uid, StringOrder.CASE_SENSITIVE) .build().findUnique()
@Transient

注解到成员属性上,代表这一个属性不被持久化到表里。java里的静态属性也不会持久化到表里。

@NameInDb("username")

指定相应成员属性在数据表里对应的数据库字段。使成员属性名和数据库名可以不一样。

@Unique

唯一约束,如果put时,将要向表里增加的记录和表里已经有一个表记录的字段值相同,则会抛异常UniqueViolationException

try {
    box.put(new User("Sam Flynn"));
} catch (UniqueViolationException e) {
    // A User with that name already exists.
}

3.Objectbox数据的增删改查

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());

//关系表查询时,会查出关联的数据,但是删除时,关联的数据并不会直接删除。

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 排序

还可以将标志传递给order()以按降序排序、区分大小写排序或特别处理空值。例如,要对上面的结果进行降序和区分大小写的排序

.order(User_.lastName, QueryBuilder.DESCENDING | QueryBuilder.CASE_SENSITIVE)

3.4.3 debugFlags

要查看ObjectBox实际执行了什么查询语句

// 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 如果有多个结果,它会抛出一个异常。
User joe = query.findUnique();

3.4.5复用query和查询参数。

如果您经常运行相同的查询,您应该缓存query对象并重用它。要使Query更具可重用性,您甚至可以在构建Query之后更改所添加的每个条件的值或查询参数,

相关方法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 分页相关,Limit, Offset, and Pagination

// offset by 10, limit to at most 5 results
//下标从0开始,包含开始下标。
List<User> joes = query.find(10, 5);

3.4.7 延迟加载 Lazy loading results

为了避免立即加载查询结果,query提供了findLazy()和findLazyCached(),它们返回查询结果的LazyList。

LazyList是一个线程安全的、不可修改的列表,它只在实体被访问时才惰性地读取实体。根据调用的find方法,懒列表是否会被缓存。缓存的惰性列表存储以前访问过的对象,以避免多次加载实体。列表的一些特性仅限于缓存列表(例如需要整个列表的特性)

3.4.8 查询结果作为一个流返回 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

返回的属性值数组没有任何特定的顺序,即使您在构建查询时指定了顺序。

String[] emails = userBox.query().build()
.property(User_.email)
.findStrings();

// or use .findString() to return just the first result

默认情况下,不返回空值。但是,如果一个属性为空,你可以指定一个替换值来返回:

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文档)还提供了聚合函数来直接计算所有发现值的最小值、最大值、平均值、总和和计数:

min() / minDouble():在匹配查询的所有对象上查找给定属性的最小值。

max() / maxDouble():找到最大值

sum() / sumDouble():计算所有值的和。注意:非双精度版本检测溢出并在这种情况下抛出异常。

avg():计算所有值的平均值(总是双精度)。

count():返回结果的数量。这比查找和获取结果数组的长度要快。可以与distinct()组合使用,只计算不同值的数量。

3.5.2 关联表查询 links Add query conditions for related entities (links)

在创建实体之间的关系之后,您可能希望为只存在于相关实体中的属性添加查询条件。在SQL中,这可以使用join来解决。但由于ObjectBox不是一个SQL数据库,我们构建了一些非常类似的东西:links。链接基于关系

假设有一个Person可以与多个Address实体相关联: ToMany 一对多关系

@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的关联Address实体,为此,使用查询构建器的link()方法来说明应该查询地址关系。然后为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 立即预取关联查询里的所有数据 Eager Loading of Relations

Only Java/Kotlin

默认情况下,关联是惰性加载的:当您第一次访问ToOne或ToMany属性时,它将执行数据库查找以获取其数据。在每次后续访问时,它将使用该数据的缓存版本。

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);

虽然初始查找速度很快,但您可能希望在返回查询结果之前预取ToOne或ToMany值。为此调用QueryBuilder。在构建查询时使用eager方法,并传递与ToOne和ToMany属性关联的RelationInfo对象来预取:

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);

只适用于深复制。

3.5.4 查询过滤器 Query filters

当您寻找需要匹配复杂条件的对象时(这些条件不能用QueryBuilder类完全表示),查询过滤器就发挥作用了。过滤器是用Java编写的,因此可以表达任何复杂性。不用说,与基于java的过滤器相比,可以更有效地匹配数据库条件。因此,当你将两者一起使用时,你将得到最好的结果:

1.使用标准数据库条件将结果缩小到合理的数量

2.现在,使用QueryFilter Java接口对这些候选者进行筛选,以确定最终结果

// 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);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容