Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This compiles for me, if this is what you were trying to achieve:</p> <pre><code> 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")) </code></pre> <p>I wouldn't recommend doing Database functions inside your case classes. We generally use case classes as simple data storing objects, and only define functions that help manage that data.</p> <p>The updating of a Member should happen in your Member DAO class, probably the simplest solution would be something like this:</p> <pre><code>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) } } </code></pre> <p>Another solution to handling modifiable classes is using a pattern along the lines of this:</p> <pre><code>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) } </code></pre> <p>And finally if you want to have a save function you could do a fluent style syntax injected through an implicit syntax, which always returns a new Member with a save function defined.</p> <pre><code>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 =&gt; member.updateFirstName(Some("First Name")).updateBirthDate(Some(new Date(123456789))).save } } } </code></pre> <p>Hope you find some of these options helpful. If I misunderstood what you're requirements are, then please comment!</p> <h2>Update</h2> <p>You don't necessarily have to have one update method for each member, but you could potentially do other logic there. If you want a simple solution then use Scala's built in copy function as you already did.</p> <pre><code>val member = MemberDao.getMember(123) val updatedMember = member.copy(birthDate = Some(new Date(123456789)), name = "Updated name") MemberDao.persist(updatedMember) </code></pre> <p>If this doesn't work for you, then please explain why.</p> <p>My problem with having a save method in a class that essentially stores data is that it doesn't take into account the <a href="http://effectivesoftwaredesign.com/2012/02/05/separation-of-concerns/" rel="nofollow noreferrer">Seperation of Concerns</a>. Also your set function has side-effects, that could confuse other developers (and isn't too functional). What if you would like to set only the firstname and then pass it onto another class to set the birthdate? Would you want to do two database transaction? I would guess not.</p> <p>That's where the <a href="https://en.wikipedia.org/wiki/Data_access_object#Advantages" rel="nofollow noreferrer">Data Access Object and its advantages</a> come into play. You would place all your database operations for a case class into one class, thereby seperating concerns: your case class holds the data and has functions that only do operations on the data, and your DAO has methods that query/persist/update/delete your case classes. This also makes testing your application easier, as it's simpler to mock a DAO than a case class' save function.</p> <p>Many people <a href="https://stackoverflow.com/questions/1748238/pros-and-cons-of-the-use-of-dao-pattern">have differing opinions on DAO's</a>, the statements are just my opinion.</p> <h2>Not using a DAO</h2> <p>I would recommend defining a trait for case classes that are updatable:</p> <pre><code>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 = ??? } </code></pre> <p>These are just ideas, I don't think there's a right or wrong solution. Choose one that makes sense to you and gives you the necessary usability/flexibility ratio.</p> <h2>Best practices</h2> <p>You asked about Scala best practices. Your question is more of a software design issue, so reading up on general OO software design can help you. Scala's case classes are just a much much easier way of writing POJOs. So before adding any new function into a case class, ask yourself the question: "Would I put this in a POJO?". If yes, then go ahead :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload