ロッドジョンソンて目がパッチリしているよ!

と伝えたかった(違

  • テーブルとテーブルの関係を管理するテーブルをつくってみる
  • IDをKeyにしてDBにインクリメントさせる。その際にnullをセットするのでIDの型をIntegerとする。
  • HSQLDBの「call identity()」というものを使ってみる。ここにAOPが使えそう。

Table定義

CREATE TABLE AUTHOR
       (authorId INTEGER IDENTITY,
        name VARCHAR(20),
        description VARCHAR(30));

CREATE TABLE BOOK_INFO
       (bookInfoId INTEGER IDENTITY,        
        isbn VARCHAR(20),
        title VARCHAR(50),
        UNIQUE (isbn));

CREATE TABLE AUTHOR_BOOK_INFO_RELATION
       (authorId INTEGER,
        bookInfoId INTEGER,
        FOREIGN KEY (authorId) REFERENCES AUTHOR (authorId) ON DELETE CASCADE,
        FOREIGN KEY (bookInfoId) REFERENCES BOOK_INFO (bookInfoId) ON DELETE CASCADE,
        UNIQUE (authorId, bookInfoId));

Entity

package sample.reading.entity;
import java.io.Serializable;

public class Author implements Serializable {
    
    public static final String TABLE = "AUTHOR";
    
    private Integer authorId;
    
    private String name;
    
    private String description;
    
    public Author() {
    }
    
    //setter & getter
}
package sample.reading.entity;
import java.io.Serializable;

public class BookInfo implements Serializable {
    
    public static final String TABLE = "BOOK_INFO";
    
    private Integer bookInfoId;
    
    private String title;
    
    private String isbn;
    
    public BookInfo() {
    }
    
    //setter & getter
}
package sample.reading.entity;
import java.io.Serializable;

public class AuthorBookInfoRelation implements Serializable{
    
    public static final String TABLE = "AUTHOR_BOOK_INFO_RELATION";
    public static final int author_RELNO = 0;
    public static final int bookInfo_RELNO = 1;
        
    private Integer authorId;
    
    private Integer bookInfoId;
    
    private Author author;
    
    private BookInfo bookInfo;
    
    //setter & getter

Dao

package sample.reading.dao;

import java.util.List;
import sample.reading.entity.*;

public interface AuthorDao {

    public Class BEAN = Author.class;
     
    public List getAllAuthors();
    
    public void insert(Author author);
    
    public void update(Author author);
    
    public void delete(Author author);
}
package sample.reading.dao;

import java.util.List;

import sample.reading.entity.BookInfo;

public interface BookInfoDao {

    public Class BEAN = BookInfo.class;
    
    public List getAllBookInfo();
    
    public void insert(BookInfo bookInfo);
    
    public void update(BookInfo bookInfo);
    
    public void delete(BookInfo bookInfo);
}
package sample.reading.dao;

import sample.reading.entity.*;

public interface AuthorBookInfoRelationDao {

    public Class BEAN = AuthorBookInfoRelation.class;
    
    public List getAll();
    
    public void insert(AuthorBookInfoRelation authorBookInfoRelation);
    
    public void update(AuthorBookInfoRelation authorBookInfoRelation);
    
    public void delete(AuthorBookInfoRelation authorBookInfoRelation);
}

Interceptor:insertのときcall identity()を実行してBeanにセットする

package sample.reading.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.extension.jdbc.SelectHandler;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.PropertyDesc;
import org.seasar.framework.beans.impl.BeanDescImpl;

public class IdentitySetInterceptor implements MethodInterceptor {
    
    private SelectHandler selectHandler;
    
    private String propertyName;
    
    public IdentitySetInterceptor() {
    }

    /**
     * @return Returns the selectHandler.
     */
    public SelectHandler getSelectHandler() {
        return selectHandler;
    }
    /**
     * @param selectHandler The selectHandler to set.
     */
    public void setSelectHandler(SelectHandler selectHandler) {
        this.selectHandler = selectHandler;
    }
    /**
     * @return Returns the propertyName.
     */
    public String getPropertyName() {
        return propertyName;
    }
    /**
     * @param propertyName The propertyName to set.
     */
    public void setPropertyName(String propertyName) {
        this.propertyName = propertyName;
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object ret  = invocation.proceed();
        Object args  = invocation.getArguments();
        if (args.length > 1) {
            throw new IllegalArgumentException("invocation='" + invocation + "'");
        }
        BeanDesc beanDesc = new BeanDescImpl(args[0].getClass()); 
        if (beanDesc.hasPropertyDesc(propertyName)) {
            PropertyDesc propertyDesc = beanDesc.getPropertyDesc(propertyName);
            propertyDesc.setValue(args[0], getIdentity());      
        }
        return ret;
    }
    
    private Object getIdentity() {
        return selectHandler.execute(new Object{});
    }
}

dicon



    
    
    
        "call identity()"
        
            
        
    

    
        
            
                "authorId"
            
        
        dao.interceptor
    

    
        dao.interceptor
    

    
        
            
                "bookInfoId"
            
                
        dao.interceptor
        

Client

package sample.reading.client;
import java.util.List;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

import sample.reading.dao.AuthorBookInfoRelationDao;
import sample.reading.dao.AuthorDao;
import sample.reading.dao.BookInfoDao;
import sample.reading.entity.Author;
import sample.reading.entity.AuthorBookInfoRelation;
import sample.reading.entity.BookInfo;

public class Client {

    private static final String PATH = "sample/reading/dicon/dao.dicon";
    private static BookInfoDao bookInfoDao;
    private static AuthorDao authorDao;
    private static AuthorBookInfoRelationDao relationDao;
    
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            bookInfoDao = (BookInfoDao)container.getComponent(BookInfoDao.class);
            authorDao = (AuthorDao)container.getComponent(AuthorDao.class);
            relationDao = (AuthorBookInfoRelationDao)container
                .getComponent(AuthorBookInfoRelationDao.class);
            run();
        } finally {
            container.destroy();
        }
    }
    
    private static void run() {
        Author author = new Author();
        author.setName("Rod Johnson");
        author.setDescription("Springの人");
        authorDao.insert(author);

        author.setDescription("目がパッチリ");
        authorDao.update(author);
        
        BookInfo bookInfo = new BookInfo();
        bookInfo.setTitle("J2EE Development without EJB");
        bookInfo.setIsbn("0-7645-5831-5");
        bookInfoDao.insert(bookInfo);
        
        AuthorBookInfoRelation relation = new AuthorBookInfoRelation();
        relation.setAuthorId(author.getAuthorId());
        relation.setBookInfoId(bookInfo.getBookInfoId());
        relationDao.insert(relation);
        List list = relationDao.getAll();
        
    }
}

実行されるSQLなど

INSERT INTO AUTHOR (name, description, authorId) VALUES('Rod Johnson', 'Springの人', null)

call identity()

UPDATE AUTHOR SET name = 'Rod Johnson', description = '目がパッチリ' WHERE authorid = 28

INSERT INTO BOOK_INFO (title, isbn, bookInfoId) 
VALUES('J2EE Development without EJB', '0-7645-5831-5', null)

call identity()

INSERT INTO AUTHOR_BOOK_INFO_RELATION (authorId, bookInfoId) VALUES(28, 28)

SELECT AUTHOR_BOOK_INFO_RELATION.authorId, AUTHOR_BOOK_INFO_RELATION.bookInfoId, 
author.name AS name_0, author.description AS description_0, bookInfo.title AS title_1, 
bookInfo.isbn AS isbn_1 
FROM AUTHOR_BOOK_INFO_RELATION 
LEFT OUTER JOIN AUTHOR author 
ON AUTHOR_BOOK_INFO_RELATION.authorid = author.authorid 
LEFT OUTER JOIN BOOK_INFO bookInfo 
ON AUTHOR_BOOK_INFO_RELATION.bookinfoid = bookInfo.bookinfoid

idをKeyにするってやったことがないので勝手がわからない。仕事ではコードが思いっきりKeyですから。計画系なのに...。自動でincrementしたらincrementされた値をとってこないと他のTableに更新できないのでcall identity()を使う必要があると思いました。そういうものでいいの?
これを見かけた方、おかしいところは突っ込んでくださいませ。

Wikiにのっけてみてもいいかなと思ったのですけどWikiの使い方よくわからない。