Search code examples
springjpakotlinspring-data-jpadata-class

Is @ManyToOne's "optional" param automatically set using Kotlin's nullability


I read that specifying optional = false in the @ManyToOne association annotation could help Spring improve the performance of the queries.

In a Kotlin data class entity, do I actually need to specify the parameter in the annotation, or can Spring figure this out by itself using the nullability of the item field?

For instance, if I have the following declaration:

@Entity
@Table(name = ACCESS_LOGS_ARCHIVES_TABLE, indexes = [
    Index(name = "access_logs_archives_item_idx", columnList = "access_item_id")
])
data class AccessLogArchive(
    val date: LocalDate,

    @ManyToOne(optional = false)
    @JoinColumn(name = "access_item_id", nullable = false) 
    val item: AccessLogItem,

    val occurrences: Int
) {
    @Id
    @GeneratedValue
    var id: Long? = null
}

@Entity
@Table(name = ACCESS_ITEMS_TABLE)
data class AccessLogItem(
    @Column(length = 3) val code: String,
    @Column(columnDefinition = "text") val path: String,
    @Column(length = 10) val verb: String
) {
    @Id
    @GeneratedValue
    var id: Long? = null
}

In this case, I would for instance expect Spring to know that the item field is not nullable, and thus the relationship should be understood as optional=false even without specifying it as I did. Is this the case?

Same question goes for the @JoinColumn's nullable = false, by the way.


Solution

  • Consider a simple entity like a Room which has a @ManyToOne relationship to House.

    @Entity
    class Room(
            @ManyToOne(optional = true)
            val house: House
    ) {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        val id: Long = 0
    }
    

    JPA will create a room table with a column

    `house_id` bigint(20) DEFAULT NULL
    

    If you specify @ManyToOne(optional = false)

    the column will look like this:

    `house_id` bigint(20) NOT NULL
    

    By specifiying optional you tell JPA how the schema should be generated, whether the column can be NULL or not.

    At runtime trying to load a Room without a House will cause an Exception if the house property is not nullable (House instead of House?) even when value of optional is true.

    The same applies to @JoinColumn.

    Is @ManyToOne's “optional” param automatically set using Kotlin's nullability?

    No it is not. It is independent from that and by default set to true.

    Conclusion: In order for you schema to reflect your entities it is a good idea to use optional = true if the house property would be nullable and optional = false if the house property would be non-nullable.