2015-02-03 12 views
11

Sto provando a mappare una riga DB con più di 22 colonne a un albero della classe del caso. Preferisco non usare HList perché non voglio lavorare con quell'API, e anche per alcuni riscontri temporali di compilazione che ho letto da qualche parte ...Mappatura personalizzata alla struttura della classe caso nidificata in Slick (oltre 22 colonne)

Ho letto questo thread risposto da Stefan Zeiger : How can I handle a > 22 column table with Slick using nested tuples or HLists?

ho visto questo test, che mostra come definire una funzione di mappatura personalizzata e mi piacerebbe farlo:

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))) 
     }) 

Il problema è che posso ce la fanno!

Ho provato con piccoli passaggi.

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) 
} 

Sembra che quando chiamo

(id, (firstName, lastName)).shaped 

Il tipo è ShapedValue[(Column[String], (Column[String], Column[String])), Nothing]

Anche se questo sembra funzionare bene

(id, firstName, lastName).shaped 

Il parametro di tipo U non è Nothing ma come previsto (String, String, String)

Non capisco davvero come funzionino tutti gli interni di Slick. Qualcuno può spiegarmi perché non riesco a far funzionare il mio codice? C'è un'importazione mancante o qualcosa del genere?

Credo che ho bisogno di ottenere un valore di tipo

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

ma non so perché mi torna Nothing e non capisco dove queste implicite Shape parametri provengono da ...

Quello che voglio è solo essere in grado di dividere facilmente la mia colonna in 2 classi case

Grazie

risposta

19

hanno anche la lo stesso problema per la limitazione di 22 colonne, il test case aiuta molto. Non so perché il codice di esempio non funziona per voi, il seguente codice funziona bene per me,

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

grazie, sembra che tu abbia ragione funziona bene. È così facile fare errori quando si hanno tuple molto grandi;) Penso di avere un problema con l'inferenza di tipo e forse un refuso quindi ho deciso di andare passo dopo passo, fornendo i tipi esplicitamente ad ogni passaggio e ora funziona –

+0

grazie , questo ha funzionato anche per me. Inoltre ho trovato un ottimo esempio su https: //lihaimei.wordpress.com/2016/03/30/slick-1-fix-più-di-22-colonne-case/ – Muhammad

8

Come rispose Izongren funziona benissimo, ma può essere difficile scrivere tale codice come è fastidioso lavorare con molto lungo tuple ... Ho deciso di farlo "passo dopo passo" e di fornire sempre i tipi esplicitamente per evitare problemi di inferenza di tipo e ora funziona bene.

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

Nel casino creato da Slick, questo è bello! – Richeek

Problemi correlati