These are chat archives for scalikejdbc/ja

9th
Mar 2016
Hiroki Shigemura
@shigemura0820
Mar 09 2016 02:23

初めまして、最近RubyからScalaに転向してきた大学生です。(とても苦しんでいます...)
SkinnyORMでDDDのリポジトリパターンを実装したいのですが、できずに困っております。。
少し長くなってしまい申し訳ありませんが、読んでいただけると幸いです。

例えば以下のようなテーブルとクラスの実装です。

テーブル

Companyテーブル

- id: Long

CompanyNameテーブル

  • company_id: Long
  • name: String

ドメインモデル

case class Company(id: Long, companyName: Option[CompanyName])
case class CompanyName(companyId: Long, name: String)

リポジトリ

CompanyRepository

object CompanyRepositryOnMySQL extends SkinnyCRUDMapper[Company] {
  override val tableName = "company"
  override def defaultAlias = createAlias("company")
  override def extract(rs: WrappedResultSet, n: ResultName[Company]): Company = {
    Company(id = rs.get(n.id))
  }

  hasOne[CompanyNameRepository](
    right = CompanyNameRepository,
    merge = (company, companyName) => company.copy(companyName = companyName)
  ).byDefault
}

CompanyName

object CompanyNameRepository extends SkinnyCRUDMapper[CompanyName] {
  override val tableName = "company_name"
  override def defaultAlias = createAlias("company_name")
  override def primaryKeyFieldName = "company_id"
  override def extract(rs: WrappedResultSet, n: ResultName[CompanyName]): Company = {
    CompanyName(
      companyId = rs.get(n.companyId),
      name = rs.get(n.name)
    )
  }
}

という実装をしてみたのですが、

このようなエラーが出ます。

play.sbt.PlayExceptions$CompilationException: Compilation error[type mismatch;
 found   : domain.models.CompanyName.type
 required: skinny.orm.feature.AssociationsFeature[domain.models.CompanyName]]

CompanyName class のコンパニオンオブジェクトにはSkinnyCRUDMapperをmixinさせていないので型が違うと怒られていると思うのですが、CompanyNameにはDB接続の責務を持たしたくないと考えています。

何か方法はありますでしょうか??

Kazuhiro Sera
@seratch
Mar 09 2016 02:52
import skinny.orm._, feature._
import scalikejdbc._
import org.joda.time._

case class Company(
  id: Long,
  companyName: Option[CompanyName] = None
)

object CompanyRepository extends SkinnyCRUDMapper[Company] {
  override val tableName = "company"
  override lazy val defaultAlias = createAlias("c")

  override def extract(rs: WrappedResultSet, rn: ResultName[Company]): Company = new Company(id = rs.get(rn.id))

  hasOneWithFk[CompanyName](
    right = CompanyNameRepository,
    fk = "company_id",
    merge = (c, name) => c.copy(companyName = name)
  ).byDefault
}

case class CompanyName(
  companyId: Long,
  name: String
)

object CompanyNameRepository extends SkinnyCRUDMapper[CompanyName] {
  override val tableName = "company_name"
  override val primaryKeyFieldName = "company_id"
  override lazy val defaultAlias = createAlias("cn")

  override def extract(rs: WrappedResultSet, rn: ResultName[CompanyName]): CompanyName = new CompanyName(
    companyId = rs.get(rn.companyId),
    name = rs.get(rn.name)
  )
}
こんな感じで。
命名規則に従わない場合、Skinny ORM の association 機能にあまり頼らずに scalikejdbc で SQL 書きながら進めるほうがいいかもしれません。あまりボイラープレートなコードが増えないアプリならなおさら。
Hiroki Shigemura
@shigemura0820
Mar 09 2016 04:35
丁寧にありがとうございます。 ちょうどORMとSQLどちらを使うべきかも検討していたところでしたのでとても参考になります。 
早速試してみます!
Manabu Nakamura
@gakuzzzz
Mar 09 2016 04:49
CompanyNameRepository の extract メソッドの戻り値型が CompanyName じゃなくて Company になってるので type mismatch になっている気がします
Kazuhiro Sera
@seratch
Mar 09 2016 04:50
元のやつですよね、そこもおかしかったし hasOne[CompanyNameRepository] も直す必要がありました。
Hiroki Shigemura
@shigemura0820
Mar 09 2016 04:52
実際は違うクラス名で実装し、モデル化するためにCompanyとCompanyNameという例を作りました。 
間違っていた箇所は編集いたします。
失礼致しました。
Manabu Nakamura
@gakuzzzz
Mar 09 2016 04:57
なるほど
Hiroki Shigemura
@shigemura0820
Mar 09 2016 09:18

先ほどはありがとうございました。解決しました。度々質問失礼します。
親テーブルのレコードをSkinnyORMを用いて削除した時に、子テーブルのレコードも削除する方法についての質問です。

Railsで言う所の、

class Company < ActiveRecord::Base
  has_one :company_option, dependent: :destroy
end

class CompanyOption < ActiveRecord::Base ; end

dependent: :destroy オプションの指定は、
SkinnyORMのhasOneや、hasManyなどでも実装できますか?? 

一応 beforeDestoyBy メソッドを使うことで似たような実装はできそうかなと思ったのですが、他に方法があれば教えてください。

Kazuhiro Sera
@seratch
Mar 09 2016 09:23
beforeDeleteBy ですね。Rails AR よりはちょっと煩雑になります。
Hiroki Shigemura
@shigemura0820
Mar 09 2016 09:23
ありがとうございます!