Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

JPA EJB3 – ví dụ mối quan hệ giữa các bảng trong CSDL

Trong ví dụ này, tôi sẽ hướng dẫn các bạn tạo 1 EJB thao tác trên nhiều bảng CSDL và giữa các bảng này có mối quan hệ với nhau.
1. Tạo Database:

Hệ cơ sở dữ liệu ở đây tôi sử dụng dùng MS SQL Server 2005. Database có tên BookMS với các bảng và mối quan hệ của chúng được cho như hình sau:
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_01.png
Đây là script sinh ra database này:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[BookType]’) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[BookType](
[typeID] [int] NOT NULL,
[typeName] [nvarchar](250) NOT NULL,
CONSTRAINT [PK_BookType] PRIMARY KEY CLUSTERED
(
[typeID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Publisher]’) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[Publisher](
[pubID] [int] NOT NULL,
[pubName] [nvarchar](150) NOT NULL,
CONSTRAINT [PK_Publisher] PRIMARY KEY CLUSTERED
(
[pubID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Book]’) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[Book](
[ISBN] [bigint] NOT NULL,
[bookTiitle] [nvarchar](250) NOT NULL,
[authorName] [nvarchar](250) NOT NULL,
[pubID] [int] NOT NULL,
[typeID] [int] NOT NULL,
[shortDesc] [ntext] NOT NULL,
CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED
(
[ISBN] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Book_BookType]’) AND parent_object_id = OBJECT_ID(N'[dbo].[Book]’))
ALTER TABLE [dbo].[Book]  WITH CHECK ADD  CONSTRAINT [FK_Book_BookType] FOREIGN KEY([typeID])
REFERENCES [dbo].[BookType] ([typeID])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Book_Publisher]’) AND parent_object_id = OBJECT_ID(N'[dbo].[Book]’))
ALTER TABLE [dbo].[Book]  WITH CHECK ADD  CONSTRAINT [FK_Book_Publisher] FOREIGN KEY([pubID])
REFERENCES [dbo].[Publisher] ([pubID])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK1FAF0945FA8708]’) AND parent_object_id = OBJECT_ID(N'[dbo].[Book]’))
ALTER TABLE [dbo].[Book]  WITH CHECK ADD  CONSTRAINT [FK1FAF0945FA8708] FOREIGN KEY([typeID])
REFERENCES [dbo].[BookType] ([typeID])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK1FAF098EFB6544]’) AND parent_object_id = OBJECT_ID(N'[dbo].[Book]’))
ALTER TABLE [dbo].[Book]  WITH CHECK ADD  CONSTRAINT [FK1FAF098EFB6544] FOREIGN KEY([pubID])
REFERENCES [dbo].[Publisher] ([pubID])

Tôi sử dụng Eclipse ganymede (3.4) để thực hiện ví dụ này.

2. Cấu hình Data Management

Bạn phải cấu hình kết nối đến CSDL trong Eclipse. Điều này bắt buộc bạn phải có JDBC driver của MS SQLServer. Bạn có thể download tại http://www.microsoft.com. Sau khi download xong, bạn giải nén ra 1 thư mục nào đó và ghi nhớ lại thư mục này, đặc biệt là file sqljdbc.jar

Trong eclipse, bạn vào menu Window->Reference, chọn mục “Data Management->Connectivity->Driver Definition” như hình
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_02.png
Nhấn nút Add để thêm, cửa sổ sau xuất hiện
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_03.png

Ở lớp Jar List, nhấn nút Add Jars/Zip… rồi chọn file jar sqljdbc.jar

Ở lớp Properties, gõ database name, gõ username, password. lưu ý phải có password. Bạn nên tạo 1 user name khác trong sqlserver với 1 pass và cấp quyền cho nó chứ không dùng sa!!!

Nhấn OK, bạn đã có 1 Driver Definition.

3. Tạo EJB Project

Trong Eclipse, bạn vào menu File->New->EJB Project. Đặt tên là BookMS_JPA. Nhấn nút Modify trong mục Configuration và nhớ chọn mục “Java Persistence 1.0“.

Nhấn Next 2 lần và chọn lựa các tùy chọn như hình sau
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_04.png
Nhấn Finish để kết thúc việc tạo EJB Project

4. Sinh ra các Entities (Entity-Bean)

Nhấn chuột phải lên project của chúng ta, chọn “JPA Tools->Generate Entities
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_05.png
Nhấn Next
https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_06.png
Nhấn Finish để kết thúc.

Bạn sẽ gặp 1 số lỗi khi xem code được phát sinh. Bạn phải fix nó bằng cách thay đổi perspective thành JPA (vào menu WIndow->Open Perspective ->Others, chọn JPA nhấn OK).

Ở góc dưới bên phải của perspective này bạn chọn tab JPA Details, thay đổi Schema thành schema mà bạn config (ở đây là dbo) như hình,

https://vovanhai.files.wordpress.com/2008/11/jpa_multitables_07.png

Sau đó lưu lại, các lỗi đã được fix.

Cấu hình persistence

Mở file Persistence.xml trong mục META-INF, thay đổi nội dung như sau

<?xml version=”1.0″ encoding=”UTF-8″?>
<persistence version=”1.0″ xmlns=”http://java.sun.com/xml/ns/persistence&#8221; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xsi:schemaLocation=”http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd”&gt;
<persistence-unit name=”EbookMS_JPA”>
<jta-data-source>java:/BOOKMSSQLDS</jta-data-source>
<properties>
<property name=”hibernate.dialect” value=”org.hibernate.dialect.SQLServerDialect” />
<property name=”hibernate.hbm2ddl.auto” value=”update” />
</properties>
</persistence-unit>
</persistence>

trong đó <jta-data-source>java:/BOOKMSSQLDS</jta-data-source> là datasource bạn cấu hình trong jboss (thay đổi nội dung file mssql-ds.xml trong %JBOSS_HOME%\server\default\deploy\, thêm vào phân đoạn

<local-tx-datasource>
<jndi-name>BOOKMSSQLDS</jndi-name>
<connection-url>
jdbc:sqlserver://localhost:1433;databaseName=BookMS
</connection-url>
<driver-class>
com.microsoft.sqlserver.jdbc.SQLServerDriver
</driver-class>
<user-name>sa</user-name>
<password></password>
<metadata>
<type-mapping>MS SQLSERVER2000</type-mapping>
</metadata>
</local-tx-datasource>

).

5. Tạo Session-Bean

Tạo package vovanhai.wordpress.sessionbean, ta sẽ viết các session bean trong package này.

Với Entity Publisher, ta sẽ tạo session bean như sau:

Tạo interface PublisherDAO.java với nội dung như sau

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Remote;

@Remote
public interface PublisherDAO {
public void addPublisher(Publisher pub);
public Publisher findPublisherByID(int id);
public Collection<Publisher>getAllPublishers();
public void removePublisher(Publisher pub);
}

Tạo bean PublisherDAOBean.java có nội dung sau

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class PublisherDAOBean implements PublisherDAO{

@PersistenceContext (name=”FirstJPAProject”)
private EntityManager entityManager;

@Override
public void addPublisher(Publisher pub) {
entityManager.persist(pub);
}

@Override
public Publisher findPublisherByID(int id) {
return entityManager.find(Publisher.class, id);
}

@SuppressWarnings(“all”)
@Override
public Collection<Publisher> getAllPublishers() {
return entityManager.createQuery(“from Publisher p”).getResultList();
}

@Override
public void removePublisher(Publisher pub) {
entityManager.remove(pub);
}

Tương tự ta tạo các sessonbean cho Book và Booktype entities

BookTypeDAO.java

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Remote;

@Remote
public interface BookTypeDAO {
public void addBookType(Booktype type);
public Booktype findBookTypeByID(int id);
public Collection<Booktype>getAllBookTypes();
}

BookTypeDAOBea.java

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class BookTypeDAOBean implements BookTypeDAO {

@PersistenceContext (name=”FirstJPAProject”)
private EntityManager entityManager;

@Override
public void addBookType(Booktype type) {
entityManager.persist(type);
}

@Override
public Booktype findBookTypeByID(int id) {
return entityManager.find(Booktype.class,id);
}

@SuppressWarnings(“all”)
@Override
public Collection<Booktype> getAllBookTypes() {
return entityManager.createQuery(“from Booktype bt”).getResultList();
}
}

BookDAO.java

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Remote;

@Remote
public interface BookDAO {
public void addBook(Book book);
public Book findBookByISBN(long isbn);
public Collection<Book>getAllBooks();
}

BookDAOBean.java

package vovanhai.wordpress.jpa;

import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class BookDAOBean implements BookDAO {
@PersistenceContext (name=”FirstJPAProject”)
private EntityManager entityManager;

@Override
public void addBook(Book book) {
entityManager.persist(book);
}

@Override
public Book findBookByISBN(long isbn) {
return entityManager.find(Book.class, isbn);
}

@SuppressWarnings(“all”)
@Override
public Collection<Book> getAllBooks() {
return (Collection<Book>)(entityManager.createQuery(“from Book c”).getResultList());
}

}

7. Tạo client để thử

package vovanhai.wordpress.jpa;

import java.util.Set;
import javax.naming.InitialContext;

public class Client {
public static void main(String[] args) {
try {
System.setProperty(“java.naming.factory.initial”,”org.jnp.interfaces.NamingContextFactory”);
System.setProperty( “java.naming.provider.url”, “localhost:1099”);
System.setProperty( “java.naming.factory.url.pkgs”, “org.jboss.naming” );

InitialContext context=new InitialContext();
BookDAO dao=(BookDAO)context.lookup(“BookDAOBean/remote”);
BookTypeDAO btdao=(BookTypeDAO)context.lookup(“BookTypeDAOBean/remote”);
PublisherDAO pubdao=(PublisherDAO)context.lookup(“PublisherDAOBean/remote”);

Book b=new Book();
b.setIsbn(3634646L);
b.setBooktiitle(“Học java bằng ví dụ”);
b.setAuthorname(“Nguyễn Văn tèo”);
b.setShortdesc(“Shordescription of this book”);

Publisher pub=pubdao.findPublisherByID(1);
b.setPubid(pub);

Booktype type=btdao.findBookTypeByID(3);
b.setTypeid(type);
dao.addBook(b);
System.out.println(“Insert “+b.getBooktiitle()+” completed…”);

//Search
Book found=dao.findBookByISBN(78354328);
System.out.println(“Search: “+found.getBooktiitle());

System.out.print(“====================List books by Publisher:”);
System.out.println(pub.getPubname()+”=================”);
Set<Book> cols=pub.getBookCollection();
for(Book b1:cols)
System.out.println(b1);
System.out.print(“====================List books by type:”);
System.out.println(type.getTypename()+”====================”);
Set<Book>bookbytype=type.getBookCollection();
for(Book bb:bookbytype)
System.out.println(bb);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Kết quả hiển thị như sau:

Insert Học java bằng ví dụ completed…
Search: JavaServer Faces
====================List books by Publisher:Deiteil=================
Tomorow Never Die
Chuyện tình
Học java bằng ví dụ
Tomorow Never Die
====================List books by type:Text Book====================
JavaServer Faces
Học java bằng ví dụ
Mastering JavaServer Faces

Chúc các bạn thành công!

12 Responses to “JPA EJB3 – ví dụ mối quan hệ giữa các bảng trong CSDL”

  1. lân said

    Lần đàu ghé vào đây…quả nhiên là 1 trang web bổ ích…Cám ơn bạn nhiều.

  2. T.Tâm said

    Đoạn code chỗ lookup:

    InitialContext context=new InitialContext();
    BookDAO dao=(BookDAO)context.lookup(”BookDAOBean/remote”);
    BookTypeDAO btdao=(BookTypeDAO)context.lookup(”BookTypeDAOBean/remote”);
    PublisherDAO pubdao=(PublisherDAO)context.lookup(”PublisherDAOBean/remote”);

    Tại sao ta không bắt đầu như sau: initialContext.lookup(“java:comp/env”)
    Có sự khác biệt nào nếu có và không có java:comp/env
    Mong nhận được phản hồi từ thầy.

  3. Quốc Khánh said

    Trong file Bean dòng này hình như không đúng

    @PersistenceContext (name=”FirstJPAProject”)

    cái này không thấy trong persistence.xml.

    Đáng lẽ phải là

    @PersistenceContext (unitName=”EbookMS_JPA”)

  4. HipSiGa said

    EM lam theo demo nay cua thay trong eclipse

    Eclipse Hellios
    Oracle Home 9i
    JDK 1.6
    Jboss 4.2.2 GA

    No bi loi “Souce not found” khi chay debug, mong thay giup em sua? a.

    Tran Trong Duc

  5. thanh said

    em bi bao loi nay :
    ids for this class must be manually assigned before calling save()
    thay chi giup em.

  6. Võ Văn Hải said

    Annotation bạn gắn cho cái ID có chắc là tự sinh không? kiểm tra lại thử!

  7. Huy said

    Em đang làm project HK 4 bằng EJB 3, em hay gặp lỗi could not load an entity khi em sử dụng 1 câu lênh select sản phẩm ra, em có kèm theo link hình

    Nếu em select tất cả Complaint thì nó lại báo lỗi ‘could not load an entity Account’, em nghỉ là do 2 bảng khóa ngoại Role và Department, khi em xóa 2 bảng đó đi thì chạy không bị lỗi nữa, em không hiểu relationship giữa các bảng này như thế nào trong EJB3, em không biết thầy có bị lỗi này chưa, nhưng em rất mong thầy có thể giải thích cho em về lỗi could not load an entity

  8. Huy said

    Em xài SQL 2008 thì MS SQLSERVER2000 em sửa như thế nào hả thầy

  9. Nhờ Anh giải giúp bài này
    For the following projects, an APDU is defined as:
    class APDU {
    private byte[] buffer;
    public byte[] getBuffer();
    public void setBuffer();
    }

    VirtualSmartCard Server (Java)
    Here we just want you to create a simple Java web service using standard technologies.

    The environment is:
    – JAX-WS 2.0 and EJB 3 annotations to create the web service
    – Deploy in JBoss
    – Build using Maven2
    – Persist objects to the database using JPA2

    The service should be called VirtualSmartCard and it should have a single method:
    – public APDU transmit(APDU apdu)

    transmit() should:
    – log the contents of the “apdu” parameter using log4j
    – save the APDU structure to a database using JPA2

    You should test this using SoapUI.

  10. Võ Văn Hải said

    cái này tốn thời gian nhiều. mình đang bận lắm. Bạn nào giúp được không?

  11. nguyenvanquan said

    Ai có thể giúp mình vấn đề này được không?
    Mình dùng netbean 6.1 server glassfish v2 mình tạo 1 cái modul EJB sau đó tạo CMP Bean.
    mình có bảng Sale(slNo, prodID) có khóa ngoại đến Product(prodID,proName)

    ở đây mình muốn hỏi truy vấn EJB Query để lấy dữ liệu của cả 2 bảng(Sale và Product)
    mình có dùng thử truy vấn : SELECT OBJECT(o) FROM Sale o, Product p
    nhưng khi chạy nó báo lỗi cột không hợp lệ PRODUCT_PRODID

    sau đó mình dùng truy vấn : SELECT OBJECT(o) FROM Sale o, IN(o.prodID) p
    thì nó lại báo lỗi : Field ‘prodID’ of type ‘Product’ is not a collection valued cmr-field.

    mình không biết sửa thế nào, mong bạn nào biết thì giúp mình với,
    bạn nào sửa được thì có thể gửi qua gmail của mình : nguyenvanquan8990@gmail.com

    cám ơn nhiều.

  12. nguyenvanquan said

    Ai có thể giúp mình vấn đề này được không ?
    Mình dùng netbean 6.1 server glassfish v2 mình tạo 1 cái modul EJB sau đó tạo CMP Bean.
    mình có bảng Sale(slNo, prodID) có khóa ngoại đến Product(prodID,proName)

    ở đây mình muốn hỏi truy vấn EJB Query để lấy dữ liệu của cả 2 bảng(Sale và Product)
    mình có dùng thử truy vấn : SELECT OBJECT(o) FROM Sale o, Product p
    nhưng khi chạy nó báo lỗi cột không hợp lệ PRODUCT_PRODID

    sau đó mình dùng truy vấn : SELECT OBJECT(o) FROM Sale o, IN(o.prodID) p
    thì nó lại báo lỗi : Field ‘prodID’ of type ‘Product’ is not a collection valued cmr-field.

    mình không biết sửa thế nào, mong bạn nào biết thì giúp mình với,
    bạn nào sửa được thì có thể gửi qua gmail của mình : nguyenvanquan8990@gmail.com

    cám ơn nhiều.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.