I understand from both personal experience and this discussion that when a data class
inherits from another class that inherited class's fields are not included in the data class's copy
function.
I'm interested in what the options are for getting around this issue.
Specifically, I have a JPA @MappedSuperClass
for my JPA entities, which are data class
es. In the super class I set up the entity ID, which (at least so far) I always want to do the same way. There are some other things I may want to do in it as well, like set up a created date, last updated date, etc.
Options I've considered so far:
Copy paste the ID, created date, etc. into every entity. Pros: it's easy and copy method works. Cons: Fails DRY and you can't handle all entities using a shared super class. (But could create an interface for that.)
Make override the super class's values and pass them to the super class.
You still need to copy paste the override values into every entity, but at least you don't have to copy the annotations.
@Entity
data class Comment(
@Lob
comment: String,
override val id: Long = -1
) : BaseEntity(id)
@MappedSuperclass
abstract class BaseEntity(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
open val id: Long = -1
)
One of the features of Kotlin data classes is that the compiler automatically derives the copy() function from all properties declared in the primary constructor. Calling the copy() function will create a new object with copies of all values from the current object.
By default, in Kotlin, classes are final and cannot be subclassed. You are only allowed to inherit from abstract classes or classes that are marked with the open keyword. Hence you need to mark the RoundHut class with the open keyword to allow it to be inherited from.
Data class inheritance (O/R Designer) Like other objects, LINQ to SQL classes can use inheritance and be derived from other classes. In code, you can specify inheritance relationships between objects by declaring that one class inherits from another.
I'm fairly certain, that because of type-erasure you aren't going to be able to accomplish this with the types of classes you have defined. Because your data class
es are extending an abstract class
is where you're going to run into many road blocks.
The easiest way to have it both ways still requires a bit of work, and there are inherent drawbacks:
fun <T: BaseEntity> T.withBase(base: BaseEntity): T {
id = base.id
return this
}
This is an easy extension method that would live next to the BaseEntity
class definition, and you would simply chain that call after .copy()
. So you would use it as follows:
val base = Comment("Created an object")
val copy = base.copy().withBase(base)
Caveats:
copy()
call will instantiate the BaseEntity
If you want the id
to increment (and any @AutoGenerated
value) when you copy, then the first caveat disappears. But, the chaining is still required, however, it does massively reduce copy/paste, and other possible errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With