ObjectBox[二] 教程:如何开始使用ObjectBox
ObjectBox[六] 数据监听和RX(Data Observers and Reactive Extensions)
ObjectBox[七] 支持LiveData(Android体系结构组件)
ObjectBox[十二] Meta Model, IDs, and UIDs
更喜欢看代码,请查看Demo。
对象可以引用其他对象,例如包含简单引用或对象列表。在数据库方面,我们称这些引用为关系。定义关系的对象我们称之为源(source)对象,被引用的对象称之为目标(target)对象。所以关系是有方向的。
如果有一个目标对象,我们称之为一对一(to one)。 如果可以有多个目标对象,我们称之为一对多(to many)。关系是懒加载的:目标对象在第一次访问时从数据库中取出。一旦目标对象被获取,它们被缓存以进一步访问。
一对一关系
您可以使用ToOne
类来定义一对一的关系 。它自动获取目标对象并缓存。例如,一个订单通常由一个客户完成。因此,我们可以将Order
类与Customer
建立一对一的关系, 如下所示:
// Customer.java
@Entity
public class Customer {
@Id public long id;
}
// Order.java
@Entity
public class Order {
@Id public long id;
public ToOne<Customer> customer;
}
现在让我们添加一个客户和一些订单。 要设置customer
对象,请 在ToOne
实例上调用 setTarget()
,并保存order
对象:
Customer customer = new Customer();
Order order = new Order();
order.customer.setTarget(customer);
long orderId = boxStore.boxFor(Order.class).put(order); // puts order and customer
如果customer
对象不存在于数据库中,则ToOne将插入它。 有关更新关系的详细信息,请参阅下文。
要在订单中获取客户customer
需要使用 getTarget()
:
Order order = boxStore.boxFor(Order.class).get(orderId);
Customer customer = order.customer.getTarget(customer);
第一次get会查询数据库调用(懒加载)。它使用ID查找,在ObjectBox中非常快。如果您只需要ID而不是整个目标对象,请调用 getTargetId()
。它可以更有效,因为它根本不查询数据库。
我们也能移除关系。如下代码:
order.customer.setTarget(null);
boxStore.boxFor(Order.class).put(order);
请注意,这不会从数据库中删除customer
,它只是消除了关系。
初始化魔法
您是否注意到 ToOne
字段customer
在上面的代码示例中从未初始化过?为什么代码仍然可以使用 ,而不会有任何NullPointerException
?因为该字段实际上是初始化的 - 初始化代码只是不可见在您的来源。ObjectBox Gradle插件调用实体类的构造函数进行初始化。因此,你可以认为 ToOne
和 ToMany / List
属性已经被初始化,并且可以使用。
对多关系
要定义多对多关系,可以使用List
类型的属性 或 ToMany
类。作为ToOne
类, ToMany
类可帮助您自动更改并将其应用于数据库。如果您不需要,请使用List
类型 并自行 处理数据库更改。
请注意, 多对多关系在第一次请求上懒加载,然后缓存在ToMany
对象内的源实体中 。所以随后调用关系的get方法不会查询数据库。
如果您需要一对多(1:N)或多对多(N:M)关系,则会有细微差别。1:N关系就像上面的例子,客户可以有多个订单,但订单只与一个客户有关。一个N:M关系的例子是学生和老师:学生可以由几个老师上课,但老师也可以指导几个学生。
一对多 (1:N):
要定义一对多关系,您需要使用@Backlink注解。它链接回目标对象中的一对一关系。使用客户和订单示例,我们可以修改客户类别,以便与客户订单具有一对多关系:
// Customer.java
@Entity
public class Customer {
@Id public long id;
@Backlink
public ToMany<Order> orders;
}
// Order.java
@Entity
public class Order {
@Id public long id;
public ToOne<Customer> customer;
}
@Backlink 告诉ObjectBox这ToOne
关系用于填充订单列表。如果 在 Order
类中有使用Customer
的多对一关系 ,则需要明确指定名称,例如 @Backlink(to = "customer")
。
让我们新建一个新客户并添加一些订单。ToMany
实现Java List接口,所以我们如下添加:
Customer customer = new Customer();
customer.orders.add(new Order());
customer.orders.add(new Order());
long customerId = boxStore.boxFor(Customer.class).put(customer); // puts customer and orders
通过访问Custom
,我们可以很容易地获得客户的订单:
Customer customer = boxStore.boxFor(Customer.class).get(customerId);
for (Order order : customer.orders) {
// TODO
}
删除订单:
Order order = customer.orders.remove(0);
boxStore.boxFor(Customer.class).put(customer);
// optional: also remove the order from its box
// boxStore.boxFor(Order.class).remove(order);
多对多关系
要定义一个多对多关系,只需使用ToMany
类添加一个属性 即可。假设一个学生和老师的例子,这是一个简单的与老师有多对多关系的学生课堂的样子:
// Teacher.java
@Entity
public class Teacher{
@Id public long id;
}
// Student.java
@Entity
public class Student{
@Id public long id;
public ToMany<Teacher> teachers;
}
给学生增加老师如下:
Teacher teacher1 = new Teacher();
Teacher teacher2 = new Teacher();
Student student1 = new Student();
student1.teachers.add(teacher1);
student1.teachers.add(teacher2);
Student student2 = new Student();
student2.teachers.add(teacher2);
// puts students and teachers
boxStore.boxFor(Student.class).put(student1, student2);
要获得学生的老师,我们只需访问这个列表:
Student student1 = boxStore.boxFor(Student.class).get(student1.id);
for (Teacher teacher : student1.teachers) {
// TODO
}
如果学生退出老师的班级,我们需要删除老师:
student1.teachers.remove(0);
// boxStore.boxFor(Student.class).put(student1);
// more efficient than using put:
student1.teachers.applyChangesToDb();
关系更新
ToOne
and ToMany
关键字帮助你维护关系,一旦你把拥有关系的对象put
进数据库,所有的变化都会应用到数据库中。
ObjectBox支持新的(尚未持久; ID为零)和现有(在ID之前持久ID是非零)对象的关系更新。
ToOne更新
ToOne
类提供以下方法来更新关系:
setTarget(entity)
设置新的目标对象; 传null
以清除关系setTargetId(entityId)
通过ID设置目标对象为数据库中已经存在的对象; 通过 0(零)清除关系
order.customer.setTarget(customer); // or order.customer.setCustomerId(customer.getId());
orderBox.put(order);
ToMany更新
ToMany
类实现了 java.lang.List
同时绑定了对象的变更。如果您将对象添加到ToMany关系中,那么这些对象将添加到数据库。类似的,如果你从ToMany关系中删除对象,那么这些对象也从关系中删除掉。请注意,从List
中删除对象并没有在数据库中删除; 只是关系被清除了。不要忘记将更改应用到数据库中。
customer.orders.add(order1);
customer.orders.remove(order2);
customerBox.put(customer);
注意:如果你已经设置@Id(assignable = true)
,这种情况下源对象还没有赋值ID,在一对多关系中增加或删除目标对象会失败。作为一种解决方法,您需要在修改关系之前增加一行代码:
customerBox.attach(customer)
customer.orders.add(order1);
customer.orders.remove(order2);
customerBox.put(customer);
例子:树型结构关系
您可以使用指向自身的to-one
和to-many
关系来构成树型结构:
@Entity
public class TreeNode {
@Id long id;
ToOne<TreeNode> parent;
@BackLink
ToMany<TreeNode> children;
}
生成的对象可让您连接父项和子项:
TreeNode parent = entity.parent.getTarget();
List<TreeNode> children = entity.children;