2015-02-03 1 views
11

22 개 이상의 열이있는 DB 행을 사례 클래스 트리에 매핑하려고합니다. 나는 그 API와 함께 일하고 싶지 않기 때문에 오히려 HList를 사용하지 않을 것이다. 그리고 어딘가에 읽은 몇 가지 기하 급수적 인 컴파일 시간 피드백에 대해서도 ...Slick (22 개 열 이상)의 중첩 된 사례 클래스 구조에 대한 사용자 지정 매핑

나는이 스레드를 Stefan Zeiger : How can I handle a > 22 column table with Slick using nested tuples or HLists?

내가 커스텀 매핑 함수를 정의하고 내가 그렇게하고 싶습니다 방법을 보여줍니다이 시험을 본 적이 :

https://github.com/slick/slick/blob/2.1/slick-testkit/src/main/scala/com/typesafe/slick/testkit/tests/JdbcMapperTest.scala#L129-141

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)

슬릭 내부가 어떻게 작동하는지 완전히 이해하지 못합니다. 누군가 내 코드 작업을 할 수없는 이유를 설명 할 수 있습니까? 누락 된 수입 등이 있습니까?

은 내가 유형

ShapedValue[(Column[String], (Column[String], Column[String])), (String, (String, String))] 

의 값을 얻을 필요가 생각하지만 ...

그것을 나에게 Nothing을 반환 이유를 알고하지 않습니다 이러한 암시 Shape 매개 변수가 어디에서 온 정말 이해가 안 돼요

는 내가 원하는 것은 단지 쉽게이 개 경우 클래스

답변

19

는 또한이 덕분에 내 열을 분할 할 수있다 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("idx_user_login", login, unique = true) 
} 
+0

감사합니다. 올바르게 작동하는 것 같습니다. 매우 큰 튜플을 사용하는 경우 오타를 만드는 것이 너무 쉽습니다.) 형식 유추 및 오타가있는 문제가있어서 단계별로 단계별로 진행하기로 결정 했으므로 각 단계마다 형식을 명시 적으로 제공하고 이제는 작동합니다. –

+0

감사합니다. , 이것도 나를 위해 일했다. 또한 https : //lihaimei.wordpress에서 아주 좋은 예를 발견했습니다.com/2016/03/30/slick-1-fix-more-than-22-columns-case/ – Muhammad

8

Izongren가 잘 작동하지만 매우 긴 작업을 짜증나으로는 코드를 작성하기 어려울 수 있습니다 대답으로 튜플 (tuples) ... 필자는 "단계별로"단계별로 결정하고 형식 유추 문제를 피하기 위해 항상 형식을 제공하기로 결정했습니다. 이제는 제대로 작동합니다.

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

슬릭이 만든 엉망으로, 이것은 아름답습니다! – Richeek

관련 문제