@Entity
public class Book {
@Id
public String isbn;
public String title;
...
Book book = em.createQuery("SELECT b FROM Book b WHERE b.isbn = :isbn", Book.class)
.setParameter("isbn", "978-4-488-10118-3")
.getSingleResult();
@StaticMetamodel(Book.class)
public class Book_ {
public static SingularAttribute< Book, String> isbn;
public static SingularAttribute< Book, String> title;
public static SingularAttribute< Book, String> author;
}
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery< Book> q = builder.createQuery(Book.class);
Root< Book> from = q.from(Book.class);
q.select(from);
q.where(builder.equal(from.get(Book_.isbn), "978-4-488-10118-3"));
Book book = em.createQuery(q).getSingleResult();
@Entity
public class Book {
@Id
public String isbn;
public String title;
...
Book book = jdbcManager.from(Book.class)
.where(eq(isbn(), "978-4-488-10118-3"))
.getSingleResult();
public interface Book extends Entity {
String getIsbn();
void setIsbn(String isbn);
...
net.java.ao.EntityManager em = ...
Book book = em.create(Book.class);
book.setIsbn("978-4-488-10118-3");
book.save();
public class Book {
@IQColumn(primaryKey = true)
public String isbn;
public String title;
...
Book b = new Book();
Book book = db.from(b)
.where(b.isbn).is("978-4-488-10118-3")
.selectFirst();
Book b = new Book();
Author a = new Author();
List< BookView> books = db.from(b)
.innerJoin(a)
.on(a.id).is(b.authorId)
.select(new BookView() {{
title = b.title;
author = a.name;
}});
whereメソッドに渡したFilterの匿名サブクラスのバイトコードを解析してクエリを組み立てる。
List< Book> books = db.from(b).where(new Filter() {
@Override
public boolean where() {
return b.isbn.equals("978-4-488-10118-3");
}
}).select();
@Entity
public class Book {
@Id
public String isbn;
public String title;
public String author;
...
@Dao(config = MyConfig.class)
public interface BookDao {
@Select
List< Book> select(String title, String author);
META-INF/app/dao/BookDao/select.sql
SELECT /*%expand*/*
FROM book
WHERE title = /* title */'x'
/*%if author != null */
AND author = /* author */'y'
/*%end*/
エンティティのフィールドやDaoのメソッドの引数、戻り値にStringなどの基本型ではなくてユーザー定義のクラスを利用できる仕組み。
@Domain(valueType = String.class, factoryMethod = "of")
public class Isbn {
private final String value;
private Isbn(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static Isbn of(String value) {
return Optional.ofNullable(value).map(Isbn::new).orElse(null);
}
}
@Entity
public class Book {
@Id
public Isbn isbn;
public Title title;
public Author author;
...
@Dao(config = MyConfig.class)
public interface BookDao {
@Select
List< Book> select(Title title, Author author);
@Select
Title selectTitle(Isbn isbn);
SQLファイルはドメインクラスを使用しない場合と何も変わらない。
SELECT /*%expand*/*
FROM book
WHERE title = /* title */'x'
/*%if author != null */
AND author = /* author */'y'
/*%end*/
@Select
List< Book> select(Title title, Author author);
@Select
List< Book> select(String title, String author);
ドメインクラスを使用していると dao.select(author, title) はコンパイルエラーになる。
例えばサロゲートキーを表すドメインクラスがあったとする。
@Domain(valueType = Long.class)
public class SurrogateKey< T> {
private final Long value;
public SurrogateKey(Long value) {
this.value = value;
}
public Long getValue() {
return value;
}
}
型変数にはエンティティをバインドする。
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public SurrogateKey< Book> id;
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public SurrogateKey< Author> id;
author.id = book.id; //コンパイルエラー
@Select
List< Book> select();
@Select(strategy = SelectType.STREAM)
< R> R select(Function< Stream< Book>, R> fn);
@Select(strategy = SelectType.COLLECT)
< R> R select(Collector< Book, ?, R> collector);
//タイトルをカンマ区切りで並べる
String titleList = select(s -> s.map(book -> book.title).collect(Collectors.joining(", ")));
@Select
Optional< String> selectTitle(Isbn isbn);
@Select
String selectTitle(Optional< Isbn> isbn);
エンティティのフィールドにもOptionalは使える。
Doma http://doma.readthedocs.org/
( Doma 1.x http://doma.seasar.org/ )
作者: @nakamura_to さん