我正在尝试将超过22列的数据库行映射到案例类树。 我宁愿不使用HList,因为我不想使用该API,也不想使用我在某处读过的指数编译时间反馈......
我读过Stefan Zeiger回答的这个帖子:How can I handle a > 22 column table with Slick using nested tuples or HLists?
我看过这个测试,它展示了如何定义自定义映射函数,我想这样做:
def * = (
id,
(p1i1, p1i2, p1i3, p1i4, p1i5, p1i6),
(p2i1, p2i2, p2i3, p2i4, p2i5, p2i6),
(p3i1, p3i2, p3i3, p3i4, p3i5, p3i6),
(p4i1, p4i2, p4i3, p4i4, p4i5, p4i6)
).shaped <> ({ case (id, p1, p2, p3, p4) =>
// We could do this without .shaped but then we'd have to write a type annotation for the parameters
Whole(id, Part.tupled.apply(p1), Part.tupled.apply(p2), Part.tupled.apply(p3), Part.tupled.apply(p4))
}, { w: Whole =>
def f(p: Part) = Part.unapply(p).get
Some((w.id, f(w.p1), f(w.p2), f(w.p3), f(w.p4)))
})
问题是我做不到!
我尝试过较小的步骤。
class UserTable(tag: Tag) extends TableWithId[User](tag,"USER") {
override def id = column[String]("id", O.PrimaryKey)
def role = column[UserRole.Value]("role", O.NotNull)
def login = column[String]("login", O.NotNull)
def password = column[String]("password", O.NotNull)
def firstName = column[String]("first_name", O.NotNull)
def lastName = column[String]("last_name", O.NotNull)
//
def * = (id, role, login, password, firstName, lastName) <> (User.tupled,User.unapply)
//
def login_index = index("idx_user_login", login, unique = true)
}
似乎在我打电话时
(id, (firstName, lastName)).shaped
类型为ShapedValue[(Column[String], (Column[String], Column[String])), Nothing]
虽然这个似乎工作正常
(id, firstName, lastName).shaped
U类型参数不是Nothing
,而是按预期(String, String, String)
我真的不明白所有Slick内部是如何工作的。有人可以解释我为什么我不能让我的代码工作?是否缺少导入或其他什么?
我想我需要获得类型
的值ShapedValue[(Column[String], (Column[String], Column[String])), (String, (String, String))]
但我不知道为什么它会返回给我Nothing
并且不太明白这些隐含的Shape
参数来自哪里......
我想要的是能够轻松地将我的专栏分成2个案例类
由于
答案 0 :(得分:21)
此外,22列限制存在同样的问题,test case非常有帮助。不知道为什么示例代码不适合你,下面的代码对我来说很好,
case class UserRole(var role: String, var extra: String)
case class UserInfo(var login: String, var password: String, var firstName: String, var lastName: String)
case class User(id: Option[String], var info: UserInfo, var role: UserRole)
class UserTable(tag: Tag) extends Table[User](tag, "USER") {
def id = column[String]("id", O.PrimaryKey)
def role = column[String]("role", O.NotNull)
def extra = column[String]("extra", O.NotNull)
def login = column[String]("login", O.NotNull)
def password = column[String]("password", O.NotNull)
def firstName = column[String]("first_name", O.NotNull)
def lastName = column[String]("last_name", O.NotNull)
/** Projection */
def * = (
id,
(login, password, firstName, lastName),
(role, extra)
).shaped <> (
{ case (id, userInfo, userRole) =>
User(Option[id], UserInfo.tupled.apply(userInfo), UserRole.tupled.apply(userRole))
},
{ u: User =>
def f1(p: UserInfo) = UserInfo.unapply(p).get
def f2(p: UserRole) = UserRole.unapply(p).get
Some((u.id.get, f1(u.info), f2(u.role)))
})
def login_index = index("id_user_login", login, unique = true)
}
答案 1 :(得分:8)
正如Izongren回答的那样工作正常,但编写这样的代码可能很难,因为使用非常长的元组很烦人...我决定“一步一步”并且总是明确地提供类型以避免类型推断问题,现在它工作正常。
case class Patient(
id: String = java.util.UUID.randomUUID().toString,
companyScopeId: String,
assignedToUserId: Option[String] = None,
info: PatientInfo
) extends ModelWithId
case class PatientInfo(
firstName: Option[String] = None,
lastName: Option[String] = None,
gender: Option[Gender.Value] = None,
alias: Option[String] = None,
street: Option[String] = None,
city: Option[String] = None,
postalCode: Option[String] = None,
phone: Option[String] = None,
mobilePhone: Option[String] = None,
email: Option[String] = None,
age: Option[AgeRange.Value] = None,
companySeniority: Option[CompanySeniorityRange.Value] = None,
employmentContract: Option[EmploymentContract.Value] = None,
socialStatus: Option[SocialStatus.Value] = None,
jobTitle: Option[String] = None
)
class PatientTable(tag: Tag) extends TableWithId[Patient](tag,"PATIENT") {
override def id = column[String]("id", O.PrimaryKey)
def companyScopeId = column[String]("company_scope_id", O.NotNull)
def assignedToUserId = column[Option[String]]("assigned_to_user_id", O.Nullable)
def firstName = column[Option[String]]("first_name", O.Nullable)
def lastName = column[Option[String]]("last_name", O.Nullable)
def gender = column[Option[Gender.Value]]("gender", O.Nullable)
def alias = column[Option[String]]("alias", O.Nullable)
def street = column[Option[String]]("street", O.Nullable)
def city = column[Option[String]]("city", O.Nullable)
def postalCode = column[Option[String]]("postal_code", O.Nullable)
def phone = column[Option[String]]("phone", O.Nullable)
def mobilePhone = column[Option[String]]("mobile_phone", O.Nullable)
def email = column[Option[String]]("email", O.Nullable)
def age = column[Option[AgeRange.Value]]("age", O.Nullable)
def companySeniority = column[Option[CompanySeniorityRange.Value]]("company_seniority", O.Nullable)
def employmentContract = column[Option[EmploymentContract.Value]]("employment_contract", O.Nullable)
def socialStatus = column[Option[SocialStatus.Value]]("social_status", O.Nullable)
def jobTitle = column[Option[String]]("job_title", O.Nullable)
def role = column[Option[String]]("role", O.Nullable)
private type PatientInfoTupleType = (Option[String], Option[String], Option[Gender.Value], Option[String], Option[String], Option[String], Option[String], Option[String], Option[String], Option[String], Option[AgeRange.Value], Option[CompanySeniorityRange.Value], Option[EmploymentContract.Value], Option[SocialStatus.Value], Option[String])
private type PatientTupleType = (String, String, Option[String], PatientInfoTupleType)
//
private val patientShapedValue = (id, companyScopeId, assignedToUserId,
(
firstName, lastName, gender, alias, street, city, postalCode,
phone, mobilePhone,email, age, companySeniority, employmentContract, socialStatus, jobTitle
)
).shaped[PatientTupleType]
//
private val toModel: PatientTupleType => Patient = { patientTuple =>
Patient(
id = patientTuple._1,
companyScopeId = patientTuple._2,
assignedToUserId = patientTuple._3,
info = PatientInfo.tupled.apply(patientTuple._4)
)
}
private val toTuple: Patient => Option[PatientTupleType] = { patient =>
Some {
(
patient.id,
patient.companyScopeId,
patient.assignedToUserId,
(PatientInfo.unapply(patient.info).get)
)
}
}
def * = patientShapedValue <> (toModel,toTuple)
}
答案 2 :(得分:0)
此外,您可以使用这种方式
class UserTable(tag: Tag) extends TableWithId[User](tag,"USER") {
def id = column[String]("id", O.PrimaryKey)
def role = column[String]("role", O.NotNull)
def extra = column[String]("extra", O.NotNull)
def login = column[String]("login", O.NotNull)
def password = column[String]("password", O.NotNull)
def firstName = column[String]("first_name", O.NotNull)
def lastName = column[String]("last_name", O.NotNull)
def loginMap = (login, password, firstName, lastName) <> (UserInfo.tupled, UserInfo.unapply)
def roleMap = (role, extra) <> (Role.tupled, Role.unapply)
override def * = (id, roleMap, loginMap) <> (User.tupled,User.unapply)
def login_index = index("idx_user_login", login, unique = true)
}