美文网首页
安卓-ObjectBox数据库笔记1:gradle配置和常用增删

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

作者: 缘焕 | 来源:发表于2021-08-31 22:26 被阅读0次

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

    相关文章

      网友评论

          本文标题:安卓-ObjectBox数据库笔记1:gradle配置和常用增删

          本文链接:https://www.haomeiwen.com/subject/uhetwltx.html