关于squeryl:如何在Scala中正确设置对象的值?

 2021-04-09 

How to properly set value of an object in Scala?

我有一个Scala def,它从HTTP POST获取参数并解析数据。我正在从数据库中提取一个"作业"对象(如在调试器中验证的那样,查询已成功完成,并且参数与所需的一样),并且尝试使用新参数更新该作业对象。但是,尝试分配值被证明是无用的,因为作业对象保留了所有原始值。

所有数据库对象均来自Squeryl。下面的代码:

编辑:在下面添加了类,并添加了Job对象以帮助在此Play中提供上下文!应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
object Job {
  def updateFromParams(params:Params) = {
    val job = Job.get( params.get("job_id").toLong ).get

    val comments =  params.get("comments")
    val startTime = parseDateTime(params.get("start_time") +"" + params.get("date"))
    val endTime = parseDateTime(params.get("end_time") +"" + params.get("date"))
    val clientId = params.get("client_id").toLong
          val client = Client.get(clientId).get
    val name = params.get("job_name")
    val startAddressType = params.get("start_address_type")
    var startLocationId:Option[Long] = None
    val (startAddress, startCity, startProvince) = startAddressType match {
      case"client" => getClientAddress(clientId)
      case"custom" => (params.get("start_custom_address"),
                params.get("start_custom_city"),
                params.get("start_custom_province"))
      case id => {
      startLocationId = Some(id.toLong)
        getLocationAddress(startLocationId.get)
      }
    }

    job.comments ->  comments
    job.startTime -> startTime
    job.endTime -> endTime
    job.clientId -> clientId
    job.name -> name
    job.startAddressType -> startAddressType
    job.startAddress -> startAddress
    job.startCity -> startCity
    job.startProvince -> startProvince


    Job.update(job)
  }
}

我很沮丧,因为如果我尝试job.name -> name不会发生任何事情,并且如果我尝试job.name = name则会出现Scala reassignment to val错误。尝试使用var name而不是val name时出现相同的错误。

这显然是我的语法问题,正确的处理方式是什么?谢谢!

更多信息:如果有帮助,这是我们的Play中使用的Job类!应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Job(
  val id: Long,

  @Column("name")
  val name: String,

  @Column("end_time")
  val endTime: Timestamp,

  @Column("start_time")
  val startTime: Timestamp,

  @Column("client_id")
  val clientId: Long,

  @Column("start_address_type")
  var startAddressType:String,

  @Column("start_address")
  var startAddress: String,
  /* LOTS MORE LIKE THIS */
) extends KeyedEntity[Long] {
}


job.name是不可变的属性,因此无法使用job.name = name更改其值。您可以在Job类的定义中看到,name是用val声明的,这意味着其值是不可变的,不能更改。"更改" Job对象的值的唯一方法是实际上创建一个全新的实例并丢弃旧的实例。在处理不可变对象时,这是标准做法。

将本地nameval更改为var无关紧要,因为您只读取该变量的值。


val是不可变的,整个Job类都是不可变的(因为所有字段都是)。

可以做的是创建一个案例类JobW和一些拉皮条功能以允许使用copy。那说:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Job(val id:Long, val name:String) {}

case class JobW(override val id:Long, override val name:String) extends Job(id, name){
  def ok:String = name + id
}

implicit def wrapJob(job:Job):JobW = JobW(job.id, job.name)

val job:Job = new Job(2L,"blah")

println(job.ok)

println(job.copy(name="Blob"))

我要做的是将一个Job(简化为练习)package到一个case类package器中,并定义隐式转换。

使用此隐式转换(称为拉皮条转换),您将可以访问ok方法,还可以访问copy方法。

copy方法是在case类上注入的一个方法,该方法接受与case类一样多的参数作为字段,并生成case类的新实例。

因此,您现在只能更改类中的一个值,非常简单,我想说的是,并可以检索一个新对象(作为不可变性的函数编程方法)。