2013-03-02 2 views
5

Mit Slick versuche ich Datenbanktabelleneinträge direkt zu der Fallklasse zu projizieren, die sie darstellen. Im Anschluss an die example in the documentation, richte ich ein zugeordnetes Projektion mit dem <> Betreiber:Mapped Projektion mit <> zu einer Fall-Klasse mit Companion-Objekt in Slick

case class SomeEntity3(id: Int, entity1: Int, entity2: Int) 

val SomeEntityTable = new Table[SomeEntity3]("some_entity_table") { 
    def id = column[Int]("id", O.PrimaryKey, O.AutoInc) 
    def entity1 = column[Int]("entity1") 
    def entity2 = column[Int]("entity2") 

    def * = id ~ entity1 ~ entity2 <> (SomeEntity3, SomeEntity3.unapply _) 
} 

Nun würde Ich mag einige statische Konstanten und Hilfsmethoden SomeEntity3 hinzuzufügen. Dazu erstelle ich ein Companion-Objekt. Aber sobald ich die Linie umfasse

object SomeEntity3 

ein ziemlich wilder mehrzeiligen Fehler für die Definition erscheint von * etwas zu sagen unleserlich über „überladene Methode Wert <> mit Alternativen“.

Wie verhält sich das Begleitobjekt zum bidirektionalen Mapping in Slick und kann ich mein Ziel irgendwie erreichen?

Antwort

8

Companion Objekte von Fallklassen in der Regel eine Funktion aus der Fallklasse -Liste erste Argument der Fall Klasse. Also, wenn Sie

case class Fnord(a: A, b: B, c: C)(d: D) 

der Compiler Scala hätte den Begleiter automatisch generieren ähnliches Objekt

object Fnord extends ((A, B, C) => Fnord) { 
    ... 
} 

Jetzt, sobald Sie explizit etwas über die Begleiter buchstabieren Objekt selbst, der Compiler nicht mehr generiert der FunctionN erweitert thingy. Daher ist es meistens eine gute Idee, es selbst hinzuzufügen. In Ihrem Fall würde bedeuten, dass der Begleiter von SomeEntity3 wie so definieren:

object SomeEntity3 extends ((Int, Int, Int) => SomeEntity3) { 
    ... 
} 

Es gibt eine (lange offen) Ausgabe für dieses Verhalten auch: https://issues.scala-lang.org/browse/SI-3664

9

Die Lösung ist ganz einfach:

def * = id ~ entity1 ~ entity2 <> (SomeEntity3.apply _, SomeEntity3.unapply _) 
+0

funktionierts, in der Tat. Eine Erklärung, warum die Rechtschreibung explizit angewendet wird, ist erforderlich und behebt das Problem hier? – notan3xit

+1

Explizites Drehen der Methode apply in eine Funktion (eta-Erweiterung) ergibt "(Int, Int, Int) => SomeEntity3", d. H. Den Typ, an dem das Companion-Objekt an erster Stelle stehen sollte. Allgemeiner ausgedrückt, wenn die Anwendungsmethode eines Funktionsobjekts in ein "neues" Funktionsobjekt umgewandelt wird, erhält man denselben Typ wie bei der ursprünglichen Funktion. –

+0

Aus irgendeinem Grund wird scalac verwirrt, wenn Sie ein Companion-Objekt haben und die Anwendung des Objekts nicht aufhebt. – pedrofurla

1

Ein anderer Weg, es zu tun ist, um die Objekte zu drehen Wenden Sie Methode in ein Tupel an und übergeben Sie diese an die <> wie unten gezeigt.

package models 

import play.api._ 
import play.api.libs.json._ 
import scala.slick.driver.H2Driver.simple._ 

case class User(
    name: String, 
    id: Option[Int] = None 
) 

object User { 
    implicit val format = Json.format[User] 
} 

class UserTable(tag: Tag) extends Table[User](tag, "USERS") { 
    def id = column[Int]("ID", O.PrimaryKey, O.AutoInc) 
    def name = column[String]("NAME", O.NotNull) 

    def * = (name, id.?) <> ((User.apply _).tupled, User.unapply) 
} 

object Users extends TableQuery(new UserTable(_)) { 
    val findByID = this.findBy(_.id) 
} 
0

persönlich die teilweise angewandt apply Methode aus der Klasse Fall nicht mit meinem Setup und Slick 3.0 arbeiten. jedoch

Dies funktioniert, auf die richtige tupled Methode gräbt indirekt:

class WidgetTable(tag: Tag) extends Table[WidgetEntity](tag, "widget_tbl") { 

    def id = column[Int]("id",O.PrimaryKey) 
    def foo = column[String]("foo") 

    override def * = (id,foo) <> ((WidgetEntity.apply _).tupled,WidgetEntity.unapply) 
} 

die vollständigen Details: https://stackoverflow.com/a/38589579/564157

Verwandte Themen