I try to implement persistent library in my android kotlin project, but catch this error on compile time:
error: Room cannot pick a constructor since multiple constructors are
suitable. Try to annotate unwanted constructors with @Ignore.
Error code:
@Entity
data class Site(
var name: String = "",
var url: String = "",
@PrimaryKey(autoGenerate = true) var id: Long = 0)
I had this error because Kotlin apparently generates multiple Java constructors for a single Kotlin constructor with default argument values. Working code see next:
@Entity
data class Site(
var name: String,
var url: String,
@PrimaryKey(autoGenerate = true) var id: Long)
None of the above solutions are good, since they work but may cause errors.
Kotlin's Data Class generates several Methods using the default constructor. That means that equals(), hashCode(),
toString(), componentN() functions and copy() is generated using the attributes you assign to your constructor.
Using the above solutions like
@Entity data class Site(@PrimaryKey(autoGenerate = true) var id: Long) {
@Ignore constructor() : this(0)
var name: String = ""
var url: String = ""
}
generates all the above listed methods only for id. Using equals leads to unwanted quality, same as toString(). Solving this requires you to have all attributes you want to process inside the constructor and add a second constructor using ignore like
@Entity data class Site(
@NonNull @PrimaryKey(autoGenerate = true) var id: Long,
var name: String = "",
var url: String = "") {
@Ignore constructor(id = 0, name = ", url = "") : this()
}
You should really keep in mind, that you usually use data classes to have methods like toString and copy. Only this solution is working to avoid unwanted bugs during runtime.
This worked for me:
@Entity
data class Site(
@PrimaryKey(autoGenerate = true) var id: Long = 0),
var name: String = "",
var url: String = "",
@Ignore var ignored: String? = null
)
this works for me
@Entity
data class TaskDetail @Ignore constructor(
@PrimaryKey(autoGenerate = true)
var id:Long = 0,
var taskId:Long = 0,
var content:String = "")
{
constructor():this(id = 0)
}
I use @Ignore to forbid ROOM warning
There are multiple good constructors and Room will pick the no-arg constructor. You can use the @Ignore annotation to eliminate unwanted constructors.
And add a default constructor for ROOM.
Here you change your app database version
and restart program agian, it will work:
@Database(entities = arrayOf(Site::class), version = 123) abstract class YourAppDatabase : RoomDatabase() {
abstract fun yourDao(): YourDao
}
and you can also try this data class
:
@Entity
data class Site(@PrimaryKey(autoGenerate = true) var id: Long) {
@Ignore constructor() : this(0)
var name: String = "",
var url: String = "",
}
and the last instruction: your primary key id
should be incremented manually.
Hope that works for you. :)
Test to show that above answers are invalid.
data class TestModel(var id: Int = 0) {
constructor() : this(0)
var name: String = "defaultname"
var testData: String = "defaulttestData"
}
val testModel = TestModel(5)
testModel.name = "test"
val testModel2 = TestModel(5)
testModel2.testData = "testdata"
testModel2.name = "test"
info { "Test with name set: $testModel" }
info { "Testdata equals Testdata2 ${testModel.equals(testModel2)}" }
returns Test with name set: TestModel(id=5) and Testdata equals Testdata2 true
Just leaving my answer in case that helps anyone. I ran into the same issue, none of the answers above worked. The only thing that worked was changing from a data class
to a class
. I invite anyone to try the same code and explain why It did the trick:
Before
@Entity
data class ImgurGalleryPost (
@NotNull @PrimaryKey
var id: String,
var title: String?,
var description: String?,
var datetime: Int?,
var cover: String?,
var coverWidth: Int?,
var coverHeight: Int?,
var accountUrl: String?,
var accountId: Int?,
var privacy: String?,
var layout: String?,
var views: Int?,
var link: String?,
var ups: Int?,
var downs: Int?,
var points: Int?,
var score: Int?,
var isAlbum: Boolean?,
var vote: Boolean?,
var favorite: Boolean?,
var nsfw: Boolean?,
var section: String?,
var commentCount: Int?,
var favoriteCount: Int?,
var topic: String?,
var topicId: Int?,
var imagesCount: Int?,
var inGallery: Boolean?,
var isAd: Boolean?,
@NotNull @Ignore
var tags: List<ImgurGalleryTag>,
var inMostViral: Boolean?,
@NotNull @Ignore
var images: List<ImgurGalleryImage>
)
After
@Entity
class ImgurGalleryPost (
@NotNull @PrimaryKey
var id: String,
var title: String?,
var description: String?,
var datetime: Int?,
var cover: String?,
var coverWidth: Int?,
var coverHeight: Int?,
var accountUrl: String?,
var accountId: Int?,
var privacy: String?,
var layout: String?,
var views: Int?,
var link: String?,
var ups: Int?,
var downs: Int?,
var points: Int?,
var score: Int?,
var isAlbum: Boolean?,
var vote: Boolean?,
var favorite: Boolean?,
var nsfw: Boolean?,
var section: String?,
var commentCount: Int?,
var favoriteCount: Int?,
var topic: String?,
var topicId: Int?,
var imagesCount: Int?,
var inGallery: Boolean?,
var isAd: Boolean?,
@NotNull @Ignore
var tags: List<ImgurGalleryTag>,
var inMostViral: Boolean?,
@NotNull @Ignore
var images:
List<ImgurGalleryImage>
)
It's really weird, but I doubt that is an Android Studio cache issue because changing it back to the data class
causes the error to show up again. Seems that is some kind of issue with the collection fields. I checked the constructor in the generated class and It looked fine, I don't know why the build was failing even when the constructor was being generated properly:
public ImgurGalleryPost(@org.jetbrains.annotations.NotNull()
java.lang.String id, @org.jetbrains.annotations.Nullable()
java.lang.String title, @org.jetbrains.annotations.Nullable()
java.lang.String description, @org.jetbrains.annotations.Nullable()
java.lang.Integer datetime, @org.jetbrains.annotations.Nullable()
java.lang.String cover, @org.jetbrains.annotations.Nullable()
java.lang.Integer coverWidth, @org.jetbrains.annotations.Nullable()
java.lang.Integer coverHeight, @org.jetbrains.annotations.Nullable()
java.lang.String accountUrl, @org.jetbrains.annotations.Nullable()
java.lang.Integer accountId, @org.jetbrains.annotations.Nullable()
java.lang.String privacy, @org.jetbrains.annotations.Nullable()
java.lang.String layout, @org.jetbrains.annotations.Nullable()
java.lang.Integer views, @org.jetbrains.annotations.Nullable()
java.lang.String link, @org.jetbrains.annotations.Nullable()
java.lang.Integer ups, @org.jetbrains.annotations.Nullable()
java.lang.Integer downs, @org.jetbrains.annotations.Nullable()
java.lang.Integer points, @org.jetbrains.annotations.Nullable()
java.lang.Integer score, @org.jetbrains.annotations.Nullable()
java.lang.Boolean isAlbum, @org.jetbrains.annotations.Nullable()
java.lang.Boolean vote, @org.jetbrains.annotations.Nullable()
java.lang.Boolean favorite, @org.jetbrains.annotations.Nullable()
java.lang.Boolean nsfw, @org.jetbrains.annotations.Nullable()
java.lang.String section, @org.jetbrains.annotations.Nullable()
java.lang.Integer commentCount, @org.jetbrains.annotations.Nullable()
java.lang.Integer favoriteCount, @org.jetbrains.annotations.Nullable()
java.lang.String topic, @org.jetbrains.annotations.Nullable()
java.lang.Integer topicId, @org.jetbrains.annotations.Nullable()
java.lang.Integer imagesCount, @org.jetbrains.annotations.Nullable()
java.lang.Boolean inGallery, @org.jetbrains.annotations.Nullable()
java.lang.Boolean isAd, @org.jetbrains.annotations.NotNull()
java.util.List<com.kimboo.core.model.ImgurGalleryTag> tags, @org.jetbrains.annotations.Nullable()
java.lang.Boolean inMostViral, @org.jetbrains.annotations.NotNull()
java.util.List<com.kimboo.core.model.ImgurGalleryImage> images) {
super();
}
If anyone can figure out a way to fix this without changing from data class
to class
please feel free to comment below.
Try to change the variable datatype from val to var :
BEFORE :
@Entity
data class Product(
@PrimaryKey
val id: String = "",
val name: String = ""
)
AFTER :
@Entity
data class Product(
@PrimaryKey
var id: String = "",
var name: String = ""
)
Error is caused by initially set variables in constructor. If you have only one constructor, change your code to this.
@Entity
data class Site(
val name: String,
val url: String,
@PrimaryKey(autoGenerate = true) val id: Long)
If you need empty constructor too, then you should do like this
@Entity
data class Site() {
constructor(name: String, url: String): this() {
this.name = name
this.url = url
}
var name: String = "",
var url: String = "",
@PrimaryKey(autoGenerate = true) var id: Long = 0
}