querydsl-scala 모듈을 통해 Scala에서 Querydsl을 사용할 수 있다. 이 모듈을 사용하려면 메이븐 빌드에 다음의 코드를 추가한다.
<dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-scala</artifactId> <version>${querydsl.version}</version> </dependency>
Scala 용 Querydsl은 표현식 생성을 위한 별도 DSL을 제공한다. Scala DSL은 가독성과 간결함을 향상시키기 위해 연산자 오버로딩, 함수 포인터, 임의 임포트 등 언어의 특징을 활용한다.
주요 대체 DSL은 다음과 같다.
//Standard Alternative expr isNotNull expr is not(null) expr isNull expr is null expr eq "Ben" expr === "Ben" expr ne "Ben" expr !== "Ben" expr append "X" expr + "X" expr isEmpty expr is empty expr isNotEmpty expr not empty // boolean left and right left && right left or right left || right expr not !expr // comparison expr lt 5 expr < 5 expr loe 5 expr <= 5 expr gt 5 expr > 5 expr goe 5 expr >= 5 expr notBetween(2,6) expr not between (2,6) expr negate -expr // numeric expr add 3 expr + 3 expr subtract 3 expr - 3 expr divide 3 expr / 3 expr multiply 3 expr * 3 expr mod 5 expr % 5 // collection list.get(0) list(0) map.get("X") map("X")
Querydsl Scala 모듈은 Querydsl의 쿼리 프로젝션을 Scala에 더욱 알맞게 만들기 위해 몇몇 임의 변환을 제공한다.
Querydsl 쿼리에서 Scala 프로젝션을 활성화하려면
RichProjectable
와 RichSimpleProjectable
래퍼를 사용해야 한다.
com.mysema.query.scala.Helpers
를 임포트 함으로써 필요한 임의 변환이 가능해진다.
예를 들어, 표준 API를 이용한 다음 쿼리는 Object[]
타입의 java.util.List
를 리턴한다.
query.from(person).list(person.firstName, person.lastName, person.age)
임의 변환을 추가함으로써, list대신에 select를 이용해서 Scala List 타입 결과를 사용할 수 있다. 또한, uniqueResult나 singleResult 대신에 unique와 single를 이용해서 Option 타입으로 결과를 사용할 수 있다.
임의 변환을 사용하면 앞서 쿼리를 다음과 같이 작성할 수 있다.
import com.mysema.query.scala.Helpers._
query.from(person).select(person.firstName, person.lastName, person.age)
이 경우 결과 타입은 List[(String,String,Integer)] 즉, Tuple3[String,String,Integer]의 List가 된다.
자바를 위한 Querydsl SQL과 마찬가지로, 쿼리를 만들려면 쿼리 타입을 생성해야 한다. 다음은 쿼리 타입 생성을 위한 코드 예제다.
빈 타입 없이 생성하기:
val directory = new java.io.File("target/jdbcgen1") val namingStrategy = new DefaultNamingStrategy() val exporter = new MetaDataExporter() exporter.setNamePrefix("Q") exporter.setPackageName("com.mysema") exporter.setSchemaPattern("PUBLIC") exporter.setTargetFolder(directory) exporter.setSerializerClass(classOf[ScalaMetaDataSerializer]) exporter.setCreateScalaSources(true) exporter.setTypeMappings(ScalaTypeMappings.create) exporter.export(connection.getMetaData)
빈 타입을 이용해서 생성하기:
val directory = new java.io.File("target/jdbcgen2") val namingStrategy = new DefaultNamingStrategy() val exporter = new MetaDataExporter() exporter.setNamePrefix("Q") exporter.setPackageName("com.mysema") exporter.setSchemaPattern("PUBLIC") exporter.setTargetFolder(directory) exporter.setSerializerClass(classOf[ScalaMetaDataSerializer]) exporter.setBeanSerializerClass(classOf[ScalaBeanSerializer]) exporter.setCreateScalaSources(true) exporter.setTypeMappings(ScalaTypeMappings.create) exporter.export(connection.getMetaData)
Querydsl Scala은 Querydls SQL을 위한 컴팩트 쿼리를 제공한다. 이 구문은 Rogue 프레임워크의 도메인 지향 쿼리 구문에서 영감을 얻었다.
RelationalPath
인스턴스를 쿼리로 임의 변환해서 도메인 지향 쿼리를 구현한다.
서비스나 DAO 클래스가 com.mysema.query.scala.sql.SQLHelpers
트레잇을 상속하면
이 기능을 사용할 수 있다.
컴팩트 쿼리를 사용하면, 쿼리의 시작 지점으로 메타 모델 클래스를 사용할 수 있다.
다음의 일반 쿼리를 사용하는 대신에
query().from(employee).select(employee.firstName, employee.lastName)
다음과 같이 Employee 또는 QEmployee의 companion 객체를 사용할 수 있다.
Employee.select(_.firstName, _.lastName)
표현식에 orderBy, where, select, single, unique를 사용하는 대신, 쿼리의 루트 표현식을 파라미터로 받고 다른 표현식을 리턴하는 함수를 사용할 수 있다. 다음은 앞 예제를 확장한 형식이다.
Employee.select({ e => e.firstName }, { e => e.lastName })
자세한 내용은 com.mysema.query.scala.sql.RichSimpleQuery
의 시그너처를 참고하기 바란다.
querydsl-maven-plugin을 이용해서 SQL 메타타입과 프로젝션을 위한 Scala 소스를 생성한다. 다음은 설정 예다.
<project> <build> <plugins> ... <plugin> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <version>${querydsl.version}</version> <configuration> <jdbcDriver>com.mysql.jdbc.Driver</jdbcDriver> <jdbcUrl>jdbc:mysql://localhost:3306/test</jdbcUrl> <jdbcUser>matko</jdbcUser> <jdbcPassword>matko</jdbcPassword> <packageName>com.example.schema</packageName> <targetFolder>${project.basedir}/src/main/scala</targetFolder> <exportBeans>true</exportBeans> <createScalaSources>true</createScalaSources> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.16</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-scala</artifactId> <version>${querydsl.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> </dependencies> </plugin> ... </plugins> </build> </project>
querydsl:export 메이븐 골을 실행한다.
다른 백엔드에 대해 쿼리를 하려면, Expression 모델을 수동으로 만들거나 별칭 함수를 사용해야 한다.
다음은 JPA를 이용할 때의 예제다.
@Entity class User { @BeanProperty @Id var id: Integer = _; @BeanProperty var userName: String = _; @BeanProperty @ManyToOne var department: Department = _; } @Entity class Department { @BeanProperty @Id var id: Integer = _; @BeanProperty var name: String = _; }
다음은 몇 가지 쿼리 예제다.
List
val person = Person as "person" query.from(person).where(person.firstName like "Rob%").list(person)
Unique result
query.from(person).where(person.firstName like "Rob%").unique(person)
Long where
query.from(person) .where(person.firstName like "Rob%", person.lastName like "An%") .list(person)
Order
query.from(person).orderBy(person.firstName asc).list(person)
Not null
query.from(person) .where(person.firstName isEmpty, person.lastName isNotNull) .list(person)
쿼리 생성을 위한 팩토리 메서드
def query() = new JPAQuery(entityManager)
위 쿼리를 실행하려면 다음과 같이 변수를 생성해야 한다.
val person = Person as "person"
하이버네이트에서 XML 기반 설정을 사용할 경우, 아직 Scala 모듈을 사용할 수 없다. HibernateDomainExporter는 현재 자바 소스 파일 생성만 지원한다.