首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kotlin JPA封装OneToMany

Kotlin JPA封装OneToMany
EN

Stack Overflow用户
提问于 2017-08-12 03:02:41
回答 2查看 10.5K关注 0票数 8

我正在使用JPA和Kotlin,并且遇到了一个试图封装OneToMany关系的问题。这是我可以用Java很容易实现的东西,但是由于Kotlin在类中只有属性和没有字段,所以有一些问题。

我有一个订单,一个订单有一对多行项目。order对象的MutableList为LineItem,但get方法不应返回可变列表或调用者可能修改的任何内容,因为这会破坏封装。order类应该负责管理行项目的集合,并确保满足所有业务规则/验证。

这是我到目前为止想出的代码。基本上,我使用了一个支持属性,它是Order类将发生变化的MutableList,然后是一个返回Iterable的瞬态属性,Collections.unmodifiableList(_lineItems)确保即使调用者获得列表,并将其转换为MutableList,他们也不能修改它。

有没有更好的方法来加强封装和完整性。也许我只是对我的设计和方法过于保守了。理想情况下,没有人应该使用getter来获取和修改列表,但是它确实发生了。

代码语言:javascript
复制
import java.util.*
import javax.persistence.*

@Entity
@Table(name = "order")
open class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long? = null

    @Column(name = "first_name")
    lateinit var firstName: String

    @Column(name = "last_name")
    lateinit var lastName: String

    @OneToMany(cascade = arrayOf(CascadeType.ALL), fetch = FetchType.LAZY, mappedBy = "order")
    private val _lineItems: MutableList<LineItem> = ArrayList()

    val lineItems: Iterable<LineItem>
    @Transient get() = Collections.unmodifiableList(_lineItems)

    protected constructor()

    constructor(firstName: String, lastName: String) {
        this.firstName = firstName
        this.lastName = lastName
    }

    fun addLineItem(newItem: LineItem) {
        // do some validation and ensure all business rules are met here

        this._lineItems.add(newItem)
    }
}

@Entity
@Table(name = "line_item")
open class LineItem {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long? = null

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "order_id", referencedColumnName = "id")
    lateinit var order: Order
        private set

    // whatever properties might be here

    protected constructor()

    constructor(order: Order) {
        this.order = order
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-31 03:24:01

你的基本想法是正确的,但我会提出一些细微的修改:

代码语言:javascript
复制
@Entity
class OrderEntity(
        var firstName: String,
        var lastName: String
) {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long = 0

    @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "order")
    private val _lineItems = mutableListOf<LineItem>()

    val lineItems get() = _lineItems.toList()

    fun addLineItem(newItem: LineItem) { 
        _lineItems += newItem // ".this" can be omitted too
    }
}

@Entity
class LineItem(
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "order_id")
        val order: OrderEntity? = null
){
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      val id: Long = 0
}

备注:

  • id不需要为空。0作为默认值已经意味着“不覆盖( persisted".
  • use )主构造函数,不需要受保护的空主构造函数(参见no-arg compiler plug-in)
  • The _ id将被自动生成并且不应该在constructor
  • since中id不是主构造函数的一部分equals将产生错误的结果(因为id将不是比较的一部分)除非以正确的方式被覆盖,因此,我不会使用data class
  • 如果lineItems是没有后备字段的属性则不需要@Transient addLineItem最好使用块体,因为它返回Unit,这也使您能够使用+=运算符而不是显式的函数调用+=
票数 6
EN

Stack Overflow用户

发布于 2018-03-31 02:16:15

首先,我喜欢使用数据类,这样你就可以免费获得equalshashCodetoString

我将所有不是集合的属性放入主构造函数中。我将集合放入类主体中。

在那里,您可以创建一个private val _lineItems,它是一个支持属性(它可以在创建val lineItems属性后由IntelliJ生成。

您的私有支持字段有一个可变的集合(我更喜欢尽可能使用Set ),可以使用addNewLineItem方法进行更改。当你得到lineItems属性时,你就得到了一个不可变的集合。(这是通过对可变列表使用.toList()来完成的。

这样,集合就被封装了,而且仍然非常简洁。

代码语言:javascript
复制
import javax.persistence.*

@Entity
data class OrderEntity(
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        val id: Long? = -1,

        var firstName: String,

        var lastName: String

) {
    @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "order")
    private val _lineItems = mutableListOf<LineItem>()

    @Transient
    val lineItems = _lineItems.toList()

    fun addLineItem(newItem: LineItem) = this._lineItems.plusAssign(newItem)
}

@Entity
data class LineItem(
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        val id: Long? = -1,

        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "order_id")
        val order: OrderEntity? = null
)
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45642181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档