【发布时间】:2018-08-22 00:32:39
【问题描述】:
假设我有一个Order 和一个User Entity,类似于这样:
User.java:
@Entity
public class User {
@PrimaryKey
public long id;
@NonNull
public String username;
}
Order.java:
@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id",
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE),
indices = @Index("user_id"))
public class Order {
@PrimaryKey
public long id;
public String description;
@ColumnInfo(name = "user_id")
public long userId;
@Ignore
private User user;
}
这样,我有一个Order,里面有一个User,在数据库中我只将这个与用户ID的关系保存为Foreign Key,而不是对象本身(它是@Ignored ),所以一切都很好并且是相关的,并且可以扩展为以几种不同的方式和查询等与其他类型一起使用。
现在的问题是,我如何获得一个 Order 对象,其中的 User 对象自动由 Room 填充?
如果我使用@Embedded,那么Order 和User 将位于同一张表上,这不利于类型的关系分离。我可以将它们与JOIN 一起返回,但这仍然只适用于具有不同名称的数据类型(也许它们都有一个名为“description”的列?),此外,插入一个Order 和一个User 在里面使用JOIN 并不简单。 @Relation 仅适用于一对多,它需要 List,这不是我的情况。
我认为@TypeConverter 可能是这里的最佳选择,在long 和User 之间进行转换,但这也很棘手。 @TypeConverter 需要对DAO 的引用,以便它可以查询User,而@TypeConverter 是由Room 调用的静态方法,因此传递DAO 可能会很棘手并导致许多代码异味,除了每个User 的额外查询将触发多个搜索,这些搜索不会在同一个@Transaction 中。
我是 Room 的新手,但我敢打赌有一个合适的方法来解决这个问题,将 Room 与原本打算使用的关系类型一起使用,我只是不知道如何让这项工作简单而完美,也不我可以在任何文档中找到它。
【问题讨论】:
-
恕我直言,使用
@Embedded是进行 1:1 映射的最简单方法。很多时候 Room 数据库只是充当服务器响应的快照,很少在上面做业务逻辑,这是服务器的职责,那么为什么我们需要这种关系分离呢? -
因为有时相同的数据会在不同的服务器响应中,所以如果我们为每个响应创建一个表,我们会浪费存储空间,例如
Order可能有一个User里面它,但Shopping Cart里面也可能有User。所以我们会在两张不同的桌子上拥有相同的User?如果User更改了他的名字并且我们在应用程序的购物车页面上获得了更新,但随后用户下线了怎么办?我们将在“订单”页面中以旧名称显示用户。如果我们尝试手动同步,如果没有关系分离,他会不会一团糟 -
这是有道理的!
-
我现在看到的唯一选择是使用@embedded 并将查询中的对象分开,以便它们从单独的表中更新、插入和选择,至少我认为这样我们可以依靠关系隔离并在数据 chenfes 时从 Room 获取自动更新(虽然不确定这个有复杂的查询)
标签: android android-room android-architecture-components android-jetpack