これがあなたが達成しようとしていたものである場合、これは私のためにコンパイルされます:
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"))
ケースクラス内でデータベース関数を実行することはお勧めしません。通常、ケース クラスは単純なデータ格納オブジェクトとして使用し、そのデータの管理に役立つ関数のみを定義します。
Member の更新は Member 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)
}
最後に、保存関数が必要な場合は、暗黙的な構文を介して挿入された流暢なスタイルの構文を実行できます。これにより、保存関数が定義された新しいメンバーが常に返されます。
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
}
}
}
これらのオプションのいくつかが役立つことを願っています。あなたの要件が何であるかを誤解している場合は、コメントしてください!
アップデート
メンバーごとに必ず 1 つの更新メソッドを用意する必要はありませんが、そこで他のロジックを実行できる可能性があります。シンプルなソリューションが必要な場合は、既に行ったように、Scala の組み込みのコピー機能を使用してください。
val member = MemberDao.getMember(123)
val updatedMember = member.copy(birthDate = Some(new Date(123456789)), name = "Updated name")
MemberDao.persist(updatedMember)
これがうまくいかない場合は、その理由を説明してください。
本質的にデータを格納するクラスに save メソッドを使用することに関する私の問題は、 Seperation of Concernsが考慮されていないことです。また、 set 関数には副作用があり、他の開発者を混乱させる可能性があります (機能的ではありません)。名のみを設定し、それを別のクラスに渡して生年月日を設定したい場合はどうすればよいでしょうか? 2 つのデータベース トランザクションを実行しますか? 私はそうではないと思います。
ここで、データ アクセス オブジェクトとその利点が発揮されます。ケース クラスのすべてのデータベース操作を 1 つのクラスに配置して、懸念事項を分離します。ケース クラスはデータを保持し、データに対する操作のみを実行する関数を持ち、DAO にはクエリ/永続化/更新/削除するメソッドがあります。ケースクラス。これにより、ケース クラスの保存関数よりも DAO をモックする方が簡単なため、アプリケーションのテストも容易になります。
多くの人が DAO について異なる意見を持っていますが、これらの記述は単なる私の意見です。
DAOを使用しない
更新可能なケース クラスのトレイトを定義することをお勧めします。
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 のケース クラスは、POJO を記述するためのはるかに簡単な方法です。そのため、新しい関数をケース クラスに追加する前に、「これを POJO に入れますか?」と自問してください。はいの場合は、先に進んでください:)