Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Scala Slick中实现类实例成员修改的最佳方法?_Scala_Mutable_Slick - Fatal编程技术网

在Scala Slick中实现类实例成员修改的最佳方法?

在Scala Slick中实现类实例成员修改的最佳方法?,scala,mutable,slick,Scala,Mutable,Slick,我试图在一个现实案例中使用Slick的方法(体育俱乐部成员个人数据的自我管理)。我已经设法从数据库中检索信息并更新记录(将成员实现为案例类并使用案例类复制方法,如下所示),但我很难找到以自然方式实现成员修改的最佳方法 我考虑了两种可能性: 1) 维护类实例的不变性并实现通用setter(参见代码) 2) 使构造函数参数为“var”(什么会抑制不变性,因此不理想) 根据选项1,我提出了以下代码(摘录,而不是全部源代码): 这不能编译,我可以想象编译器为什么不高兴(虽然当前的实现似乎可以工作),但我

我试图在一个现实案例中使用Slick的方法(体育俱乐部成员个人数据的自我管理)。我已经设法从数据库中检索信息并更新记录(将成员实现为案例类并使用案例类复制方法,如下所示),但我很难找到以自然方式实现成员修改的最佳方法

我考虑了两种可能性: 1) 维护类实例的不变性并实现通用setter(参见代码) 2) 使构造函数参数为“var”(什么会抑制不变性,因此不理想)

根据选项1,我提出了以下代码(摘录,而不是全部源代码):

这不能编译,我可以想象编译器为什么不高兴(虽然当前的实现似乎可以工作),但我也可以想象它可以工作。不管怎样:有人看到了实现这一目标的方法吗

或者,有人会推荐什么作为最佳实践来为光滑的持久化对象实现可修改的类实例

提前谢谢你的提示


关于

这是为我编写的,如果这是您试图实现的:

  def set(name: String = name, firstname: Option[String] = firstname, birthDate : Option[Date] = birthDate)(implicit session: Session) = {
    val m = Member(id, name, firstname, birthDate, gender, country, healthNotes)
    Members.update(m)
    m
  }
...
member.set(firstname = Some("name"))   
我不建议在case类中执行数据库函数。我们通常使用用例 类作为简单的数据存储对象,并且只定义有助于管理该数据的函数

成员的更新应该发生在您的成员DAO类中,最简单的解决方案可能是这样的:

object MemberDao {
  def updateMemberDetails(member: Member, name: String, firstname: Option[String], birthdate : Option[Date]) = {
    val updatedMember = member.copy(name = name, firstname = firstname, birthDate = birthdate)
    Members.update(updatedMember)
  }
}
处理可修改类的另一个解决方案是使用如下模式:

case class Member(id: Int, name: String, firstname: Option[String] = None, birthDate: Option[Date] = None, gender: Option[String] = None, country: Option[String] = None, healthNotes: Option[String]) {
  def updateName(n: String) = this.copy(name = n)
  def updateFirstName(fn: Option[String]) = this.copy(firstname = fn)
  def updateBirthDate(bd: Option[Date]) = this.copy(birthDate = bd)
}
最后,如果你想要一个save函数,你可以通过隐式语法注入一个流畅的语法,它总是返回一个定义了save函数的新成员

case class Member(id: Int, name: String, firstname: Option[String] = None, birthDate: Option[Date] = None, gender: Option[String] = None, country: Option[String] = None, healthNotes: Option[String])

object Updatable {
  implicit class UpdatableMember(member: Member) {
    def updateName(n: String) = member.copy(name = n)
    def updateFirstName(fn: Option[String]) = member.copy(firstname = fn)
    def updateBirthDate(bd: Option[Date]) = member.copy(birthDate = bd)
    def save(implicit session: Session) = {
      ???
    }
  }
}

object MemberDao {
  def updateMember(member: Member) = {
    import Updatable._
    DB withSession { implicit session =>
      member.updateFirstName(Some("First Name")).updateBirthDate(Some(new Date(123456789))).save
    }
  }
}
希望这些选项对您有所帮助。如果我误解了你的要求,请评论

更新 您不必为每个成员都有一个更新方法,但您可以在那里执行其他逻辑。如果您想要一个简单的解决方案,那么可以像以前一样使用Scala的内置复制功能

val member = MemberDao.getMember(123)
val updatedMember = member.copy(birthDate = Some(new Date(123456789)), name = "Updated name")
MemberDao.persist(updatedMember)
如果这对你不起作用,那么请解释原因

在本质上存储数据的类中使用save方法的问题是,它没有考虑。此外,set函数还有副作用,这可能会让其他开发人员感到困惑(而且功能性不强)。如果您只想设置firstname,然后将其传递到另一个类以设置生日,该怎么办?是否要执行两个数据库事务?我想不会

这就是问题的症结所在。您可以将一个case类的所有数据库操作放在一个类中,从而分离关注点:您的case类保存数据并具有仅对数据执行操作的函数,而DAO具有查询/持久化/更新/删除您的case类的方法。这也使得测试应用程序更容易,因为模拟DAO比模拟case类的保存函数更简单

很多人,这些说法只是我的看法

不用刀 我建议为可更新的案例类定义一个特征:

trait DatabaseAccess[T] {
  def create(implicit session: Session): T
  def update(implicit session: Session): T
  def delete(implicit session: Session): Boolean
}

case class Member(id: Int, name: String, firstname: Option[String] = None, birthDate: Option[Date] = None, gender: Option[String] = None, country: Option[String] = None, healthNotes: Option[String]) extends DatabaseAccess[Member] {
  def create(implicit session: Session): Member = ???
  def delete(implicit session: Session): Boolean = ???
  def update(implicit session: Session): Member = ???
}
这些只是想法,我不认为有正确或错误的解决方案。选择一个对你有意义并能给你必要的可用性/灵活性比率的

最佳做法
您询问了Scala的最佳实践。你的问题更多的是一个软件设计问题,所以阅读一般的OO软件设计可以帮助你。Scala的case类只是编写POJO的一种简单得多的方法。因此,在将任何新函数添加到case类中之前,请先问自己一个问题:“我会将其放入POJO中吗?”。如果是,那么继续:)

事实上,如果参数和默认值使用相同的名称,则原始代码可以工作。只有Scala IDE中的语法高亮显示似乎不理解:如果名称不同,则默认值(正确地)高亮显示为类成员,但它们只是显示为参数本身,其中名称相同

此处为当前版本(按预期工作,但语法未正确突出显示):

注意:字符串参数最好也作为选项[String]传递

欢迎提出意见和建议


问候

Hello Krivachy.Achos,首先,感谢您的详细回答和花时间记录。这些肯定是相关和有趣的评论,我将更详细地研究它们。关于代码,是的,它可以编译,但我担心-仅基于语法突出显示:-(,我承认-“name”与命名参数相同。这就是我试图限定它的原因。如果我的看法是正确的,默认值没有效果。现在,关于“fluent”方法和DAO,这正是我想要避免的:使用case类(a.o.避免使用setter和getter“a la JavaBean”)有什么意义如果每个成员必须实现一个更新方法?第二,这是一个真实的问题-在哪里可以找到关于案例类和数据库访问的最佳实践?我的意思是:我拥有并定期重读“Scala编程,第二版”(Odersky,Spoon and Venners)在课堂上,我不知道方法是什么。他们的例子似乎是相反的。你能提供一些指导或详细说明吗?提前感谢。这是一个有效的方法,我认为这是正确的答案。你不想让它们像@krivachy.akos一样,你只需将set方法移动到dao调用is setMember中,并将member对象作为第一个参数传递。这个答案与在copy方法中构建的Scala case类没有区别,它做的事情完全相同。如果你计划
val member = MemberDao.getMember(123)
val updatedMember = member.copy(birthDate = Some(new Date(123456789)), name = "Updated name")
MemberDao.persist(updatedMember)
trait DatabaseAccess[T] {
  def create(implicit session: Session): T
  def update(implicit session: Session): T
  def delete(implicit session: Session): Boolean
}

case class Member(id: Int, name: String, firstname: Option[String] = None, birthDate: Option[Date] = None, gender: Option[String] = None, country: Option[String] = None, healthNotes: Option[String]) extends DatabaseAccess[Member] {
  def create(implicit session: Session): Member = ???
  def delete(implicit session: Session): Boolean = ???
  def update(implicit session: Session): Member = ???
}
 def set(name: String = name, firstname: String = firstname, birthDate : Option[Date] = birthDate,
        gender: String = gender, country: String = country, 
        addressBlockId: Option[Int] = addressBlockId, healthNotes: String = healthNotes)
        (implicit session: Session) = { 
    val m = this.copy(id,name,Option(firstname),birthDate,
        Option(gender),Option(country),addressBlockId,Option(healthNotes))
    m
  }