tldr;
У тебя класс без data!
Да, неплохой такой класс
Использовать data class для JPA сущности оправдано, если id записи генерится на стороне приложения и избыточно, если id генерится на стороне базы данных, так как придется переопределять методы equals и hashcode.
Подробности
Есть класс, отмеченный аннотацией @Entity и @Table. Нужно ли добавлять data перед class?
@Table
@Entity
class Entity(
@Id
val id: SomeIdentityType,
@Column
val name: String
)Ответ на вопрос зависит от того, где генерится id, но вначале разберемся с data class. Data class были созданы для тех, кому лень переопределять методы. Ниже написан data class и представлен bytecode.
data class D(val name: String)Из bytecode я удалил "лишнее" и оставил только необходимое для дальнейших рассуждений.
public static final class D {
@NotNull
private final String name;
@NotNull
public final String getName() {
return this.name;
}
@NotNull
public String toString() {
return "D(name=" + this.name + ")";
}
public int hashCode() {
String var10000 = this.name;
return var10000 != null ? var10000.hashCode() : 0;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Scratch_7.D) {
Scratch_7.D var2 = (Scratch_7.D)var1;
if (Intrinsics.areEqual(this.name, var2.name)) {
return true;
}
}
return false;
} else {
return true;
}
}
}Таким образом, data перед class это указание компилятору переопределить методы toString(), equals(), hashCode() на основании данных полей конструктора.
JPA Entity это объекты, которые отображают поля объекта на строки в таблице базе данных. На первый взгляд data класс это то, что нуж��о, но тут есть несколько моментов (не нюансов). По сути все крутится вокруг поля, которое отображается на "первичный ключ" (id). Id может быть сгенерирован как со стороны приложения, так и со стороны базы данных. В первом случае нужен тип, который однозначно идентифицирует запись и примером такого типа может быть UUID.
@Table
@Entity
data class EntityApp(
@Id
val id: UUID,
@Column
var name: String
)
@Test
fun `test app generated id`() {
val name = "имя"
val id = UUID.randomUUID()
val (entity1, entity2) = EntityApp(id, name) to EntityApp(id, name)
val m = mutableMapOf<EntityApp, String>()
m[entity1] = "Найден"
println("До сохранения в б.д.")
println("${entity1 == entity2}") // true
val result = entityAppRepository.save(entity1)
println("После сохранения в б.д.")
println("${entity1 == result}") // true
println("${entity1 == entity2}") // true
println(m[entity1] ?: "Не найден") // Найден
}Получается, что написать data перед class для JPA Entity оправдано, если id генерится на стороне приложения.
Теперь рассмотрим случай, когда id генерится на стороне базы данных.
@Table
@Entity
data class EntityDb(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column
var name: String
)
@Test
fun `test db generated id`() {
val name = "имя"
val (entityDb1, entityDb2) = EntityDb(name = name) to EntityDb(name = name)
val m = mutableMapOf<EntityDb, String>()
m[entityDb1] = "Найден"
println("До сохранения в б.д.")
println("${entityDb1 == entityDb2}") // true
val result = entityDbRepository.save(entityDb1)
println("После сохранения в б.д.")
println("${entityDb1 == result}") // true
println("${entityDb1 == entityDb2}") // false
println(m[entityDb1] ?: "Не найден") // Не найден
}Объект оказался изменён после сохранения и поэтому entityDb1 != entityDb2. Автоматически переопределенный метод equals содержал проверку на id == other.id. До сохранения id был null, а после принял значение равное id из базы. entityDb1 добавлен в hashmap, но после сохранения в б.д. hashcode изменился (так как изменился id) и теперь entityDb1 не найти в hashmap после сохранения. Оба метода требуют переопределения и указание data class для JPA Entity избыточно. Кстати, автоматически переопределённый метод toString наглядно демонстрирует side эффект, когда id для объекта не задан до сохранения в базу данных и id получает значение после сохранения в базу данных.
Использовать data class для JPA сущности оправдано, если id записи генерится на стороне приложения и избыточно, если id генерится на стороне базы данных, так как придётся переопределять методы equals и hashcode.
