android 房间库-具有自动生成关键字的表之间的关系

jchrr9hc  于 2023-02-06  发布在  Android
关注(0)|答案(3)|浏览(113)

我遇到的例子是没有主键的关系,我的数据库模式如下。
我在两个表中都有主键,并且我正尝试创建一个DAO方法,该方法将连接user表和department表以显示一条记录。

    • 问题**,如何创建一个DAO方法来访问由部门信息连接的记录。如果可能的话,我更喜欢不创建更多的数据类。例如使用Map<User, Department>。如果没有,我将接受其他解决方案。
    • 用户表**
+----+----------+----------+---------------+
| id | username |   name   | department_id |
+----+----------+----------+---------------+
|  1 | johndoe  | John Doe |             3 |
|  2 | janedoe  | Jane Doe |             4 |
+----+----------+----------+---------------+
    • 用户数据类**
@Entity(tableName = "user")
data class User(
    @PrimaryKey (autoGenerate = true) var id: Long,
    var username: String,
    var name: String,
    var department_id: Long)
    • 部门表**
+----+----------------+
| id |      name      |
+----+----------------+
|  1 | Sales          |
|  2 | Account        |
|  3 | Human Resource |
|  4 | Marketing      |
+----+----------------+
    • 部门数据类**
@Entity(tableName = "department")
data class Department(
    @PrimaryKey(autoGenerate = true) var id: Long,
    var name: String)

"我对DAO的尝试"

@Dao
interface UserDAO {

    @Query("SELECT user.*, department.name AS 'department_name' FROM user " +
            "INNER JOIN department ON user.department_id = department.id " +
            "WHERE user.id = :id")
    fun findById(id: Long): Map<User, Department>
}
    • 编辑**

如果Department是在User内部组成的,它会起作用吗?如果是这样的话,那么DAO内部的查询看起来会是什么样子?

@Entity(tableName = "user")
data class User(
    @PrimaryKey (autoGenerate = true) var id: Long,
    var username: String,
    var name: String,
    @Embedded var department: Department)

data class Department(
    @PrimaryKey(autoGenerate = true)
    var id: Long,
    var name: String? = null): Parcelable
    • DAO尝试**
@Query("SELECT * FROM user " +
    "INNER JOIN department d ON department.id = d.id " +
    "WHERE id = :id")
fun findById(id: Long): Map<User, Department>
1mrurvl1

1mrurvl11#

由于列名(id和name)不明确,您的代码按但是的方式工作,值与预期不符。
以下是调试时的结果(注意用户ID是500和501,而不是1和2,以便更好地突出显示问题),断点位于适当的位置,并且使用:-

findById(500)

然后调试器显示:-

也就是说,尽管John的部门ID是3,但在部门本身中却是500,同样,部门名称是***John Doe***,而不是预期的*Human Resource
这是因为Room不知道哪个id代表什么,同样也不知道name。
修复方法是使用唯一的列名,例如:-

@Entity(tableName = "department")
data class Department(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "dept_id")
    var id: Long,
    @ColumnInfo(name = "dept_name")
    var name: String
 )
  • 例如,表中的列已更改,但部门中的列未更改。您可以只将字段的名称更改为唯一名称。

显然,如果列名发生变化,则SQL必须相应地进行更改,因此:-

@Query("SELECT * FROM user " +
        "INNER JOIN department ON department_Id = dept_id " +
        "WHERE id = :id")
fun findById(id: Long): Map<User, Department>
  • 由于列名称现在没有歧义,所以不需要使用表名来区分(你仍然可以。2没有表巴内斯,SQL可以更简洁。

现在调试显示:-

其他重新编辑

如果部门是在用户内部组成的,是否可以?
如果您在@Entity注解类(包含在@Database注解类的entities参数中)中使用@Embedded,则生成的表将具有与嵌入类相同的列。
如果嵌入的类以前是一个表,那么就不存在的关系而言,以前的表很可能是失效的。
嵌入的Department存在一个问题,因为您将有两列名为id
从数据库的Angular 来看,如果是一对多关系,则相同的数据(例如人力资源)将重复,这与标准化相反。
关于这个问题

@Query("SELECT * FROM user " +
    "INNER JOIN department d ON department.id = d.id " +
    "WHERE id = :id")
fun findById(id: Long): Map<User, Department>

那么这将不起作用,因为没有department表(因为根据您的代码,Department类没有用@Entity注解)。

pxy2qtax

pxy2qtax2#

正如官方文档中所描述的,房间从2.4版本开始就支持这个功能。与您类似的问题似乎也在这个答案https://stackoverflow.com/a/72990697/5473567中得到了解决
在你的具体例子中,你忘记了关系是1:N,因此你在DAO函数中的返回类型应该看起来像Map<User, List<Department>>
SELECT中的department.name AS 'department_name'也是错误的。data class Department中的字段name名为name,因此在数据库表department中,此字段也将名为name。如果要将其名称更改为SELECT中使用的department_name,你必须使用注解@ColumnInfo,如下所示:

@Entity(tableName = "department")
data class Department(
    @PrimaryKey(autoGenerate = true) var id: Long,
    @ColumnInfo(name = "department_name") var name: String
)

最后一个提示,如果您正在从数据库中提取完整的数据,那么有足够的数据可以使用SELECT * FROM...,Room将为您解决这个问题。
最后,整个DAO接口可能看起来像这样:

@Dao
interface UserDAO {
    @Query("SELECT * FROM user " +
        "INNER JOIN department ON user.department_id = department.id " +
        "WHERE user.id = :id")
    fun findById(id: Long): Map<User, Department>
}
ozxc1zmp

ozxc1zmp3#

解决了。根据答案,下面是我的解决方案,不使用额外的数据类,同时保持列名不变,例如在每个表中使用不带任何前缀的id列(更可取)。我不得不在WHERE子句中使用user.id以避免歧义

    • 用户**
@Entity(tableName = "user")
data class User(
    @PrimaryKey (autoGenerate = true) 
    var id: Long,
    var username: String,
    var name: String,
    var department_id: Long)
    • 部门**
@Entity(tableName = "department")
data class Department(
    @PrimaryKey(autoGenerate = true)
    var id: Long,
    var name: String)
    • DAO查询**
@Query("SELECT * FROM user " +
        "INNER JOIN department ON user.department_id = department.id " + // fixed from user.id = department.id
        "WHERE user.id = :id")
fun find(id: Long): Map<User, Department>

相关问题