如何使主键作为房间持久性库的自动增量
Posted
技术标签:
【中文标题】如何使主键作为房间持久性库的自动增量【英文标题】:How to make primary key as autoincrement for Room Persistence lib 【发布时间】:2017-10-21 22:11:18 【问题描述】:我正在创建一个实体 (Room Persistence Library) 类 Food,我想将 foodId
设为自动增量。
@Entity
class Food(var foodName: String, var foodDesc: String, var protein: Double, var carbs: Double, var fat: Double)
@PrimaryKey
var foodId: Int = 0
var calories: Double = 0.toDouble()
如何将foodId
设置为自增字段?
【问题讨论】:
你可以使用0.0
而不是 0.toDouble()
将其声明为双精度
如何创建 Food 类的新实例?您是手动指定 ID 还是将其留空?
给未来读者的注意事项 - Room 的主键必须为 0 才能将其视为未设置。如果您使用任何其他默认值(例如 -1),Room 将不会自动生成 id。
【参考方案1】:
在这么多答案之后,这令人难以置信,但最后我的做法并没有什么不同。我不喜欢主键可以为空,我想把它作为第一个参数,也想插入而不定义它,它也不应该是 var。
@Entity(tableName = "employments")
data class Employment(
@PrimaryKey(autoGenerate = true) val id: Long,
@ColumnInfo(name = "code") val code: String,
@ColumnInfo(name = "title") val name: String
)
constructor(code: String, name: String) : this(0, code, name)
【讨论】:
现在,您如何在不传递 id 作为参数的情况下调用此类 Employee?请告诉。 @JaiminModi 你在那里看到二级构造函数吗?你可以称之为就业(代码=“代码”,名称=“名称”)或简单的就业(“代码”,“名称”) 在这种情况下甚至不需要创建额外的构造函数。只需将 0 作为默认参数添加到 id 中,您就可以自动使用构造函数,而无需额外声明:@PrimaryKey(autoGenerate = true) val id: Long = 0L, 如果您添加默认值作为第一个参数,您将自动能够在没有此额外声明的情况下使用构造函数,这不是真的。在这种情况下,您将不得不使用命名参数,这在我的情况下大多是不可取的,所以这就是这里需要辅助构造函数的原因。 我的意思是,在构造一个需要这么多字符串、整数和长整数作为参数的类时使用命名参数可能是更好的方法。【参考方案2】:使用下面的代码注释您的实体类。
在 Java 中:
@PrimaryKey(autoGenerate = true)
private int id;
在 Kotlin 中:
@PrimaryKey(autoGenerate = true)
var id: Int
Room 会自动生成并自动增加 id 字段。
【讨论】:
【参考方案3】:这对我有用:
@Entity(tableName = "note_table")
data class Note(
@ColumnInfo(name="title") var title: String,
@ColumnInfo(name="description") var description: String = "",
@ColumnInfo(name="priority") var priority: Int,
@PrimaryKey(autoGenerate = true) var id: Int = 0//last so that we don't have to pass an ID value or named arguments
)
请注意,在将实体插入到 Room 之前,id 是最后一个,以避免在创建实体时必须使用命名参数。将其添加到房间后,在更新实体时使用 id。
【讨论】:
【参考方案4】:添加@PrimaryKey(autoGenerate = true)
@Entity
public class User
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "full_name")
private String name;
@ColumnInfo(name = "phone")
private String phone;
public User()
//type-1
public User(String name, String phone)
this.name = name;
this.phone = phone;
//type-2
public User(int id, String name, String phone)
this.id = id;
this.name = name;
this.phone = phone;
同时存储数据
//type-1
db.userDao().InsertAll(new User(sName,sPhone));
//type-2
db.userDao().InsertAll(new User(0,sName,sPhone));
类型 1
如果您没有为主键传递值,默认情况下它将为 0 或 空。
类型 2
在创建对象(我的案例用户对象)时为 id 设置 null 或零
如果字段类型是 long 或 int(或其 TypeConverter 将其转换为 long 或 int),则 Insert 方法在插入项目时将 0 视为未设置。
如果字段的类型是 Integer 或 Long (Object)(或其 TypeConverter 将其转换为 Integer 或 Long),则 Insert 方法在插入项目时将 null 视为未设置。
【讨论】:
我们能否将自定义 id 传递给实体,即使它设置为自动生成? @Igor Ganapolsky 是的,但是条目将使用该自定义 id 生成 [自动增量将不起作用] 如果您再次传递相同的 id,它将抛出异常“唯一约束失败”,因此您需要始终通过新 id 或设为 [0 或 null] 并让自动增量为您完成这项工作。 如果您想自动生成,为什么还要让用户将 id 放入构造函数中? 在 Kotlin 中,您可以使用数据类并编写:val jack = User(name = "Jack", phone= 1)
在这种情况下,您可以从构造函数中删除 0
@hellcast 如果你没有在构造函数中包含 id (正如我刚刚学到的艰难方法),当你查询数据库时,它不会分配 id 字段(它只是你在构造函数中初始化它),因为我假设它在填充对象的字段时调用相同的构造函数。【参考方案5】:
您需要使用autoGenerate
属性
你的主键注释应该是这样的:
@PrimaryKey(autoGenerate = true)
PrimaryKey 的参考。
【讨论】:
谢谢,我在找autoIncrement,所以没找到。 嘿@MatPag 如果我想要一个表中的两个主键(复合主键)并且主键之一应该自动递增怎么办?我怎样才能做到这一点?你能回答这个here 吗? @MatPeg 如果我想要一个 PrimaryKey 是自己生成的,而另一个来自 REST@Entity( primaryKeys = arrayOf(COLUMN_ID_LOCAL,COLUMN_ID_REMOTE))
怎么办?
@murt 你需要一个复合主键,但你不能做你想做的事。阅读here
链接文档的重要部分:Insert methods treat 0 as not-set while inserting the item.
【参考方案6】:
例如,如果您想要存储一个 users
实体,其中包含字段 (firstname, lastname , email)
并且您想要自动生成的 id,那么您可以这样做。
@Entity(tableName = "users")
data class Users(
@PrimaryKey(autoGenerate = true)
val id: Long,
val firstname: String,
val lastname: String,
val email: String
)
Room 将自动生成并自动增加 id
字段。
【讨论】:
每次我们创建一个新的 Users 对象时,我们都需要传递一个 id 字段。这可以避免吗? 是的,把@PrimaryKey(autoGenerated = true) val id: Long? = null
放在构造函数之外,放在类的主体上
@Magritte Care 请详细说明?
@Ispam 在我上面的回答中,我发布了完整类的外观。
其实你可以简单的把0作为ID。如果你设置了@PrimaryKey 选项,房间会自动生成一个ID。【参考方案7】:
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true) var id: Int?,
var name: String,
var dob: String,
var address: String,
var gender: String
)
constructor():this(null,
"","","","")
【讨论】:
虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 有很多答案,比如“使用@PrimaryKey(autoGenerate = true)
”——你的答案是否为这个线程添加了任何新内容?
是的,它添加了 - 它展示了 null 如何覆盖自动生成的字段【参考方案8】:
您可以像这样添加@PrimaryKey(autoGenerate = true)
:
@Entity
data class Food(
var foodName: String,
var foodDesc: String,
var protein: Double,
var carbs: Double,
var fat: Double
)
@PrimaryKey(autoGenerate = true)
var foodId: Int = 0 // or foodId: Int? = null
var calories: Double = 0.toDouble()
【讨论】:
foodId
不需要为空(但可以)。也可以使用默认值,例如。 var foodId: Int = 0
并且自动生成将正常工作。
@MichałBaran,来自 java doc,当类型是原始 java int
或 long
,0 被视为可空,当类型为 Integer 或 Long 时,null 是可以为空。由于 Kotlin Int 当不可为空在 JVM 中作为原始 int 工作时,那么你是对的,var foodId: Int = 0
可以工作,但 var foodId: Int? = 0
将不能工作,因为 Int?在 JVM 中转换为整数。 @JMK,如果您将其设为 0,则出于上述原因,您必须创建一个不可为空的 int
。
你可以不用其他方式写:val jack = User(name = "Jack", phone= 1)
在这种情况下你可以从构造函数中删除 0
我看到这种方法的问题在于它是一个数据类。当 Food 是一个数据类时(如在 sn-p 中),food 用于 equals() 比较,因此可以认为具有不同 foodId 的两种食物是相等的。使用带有默认值的命名参数将解决这个问题。
@neer17 因为 foodId 将在插入时由 Room 自动生成,所以在构造函数中使用它更可能没有用。以上是关于如何使主键作为房间持久性库的自动增量的主要内容,如果未能解决你的问题,请参考以下文章