Статьи

NoSQL с JPA

EclipseLink , эталонная реализация JPA, имеет поддержку JPA для баз данных NoSQL (MongoDB и Oracle NoSQL) начиная с версии 2.4. В этом руководстве мы обсудим использование базы данных MongoDB с поддержкой JPA EclipseLink. Транзакция, ранее выполненная с использованием консоли и собственного драйвера java, будет выполнена в веб-приложении с помощью EclipseLink.

Инструменты и технологии, используемые в примере приложения, следующие:

  • MongoDB версия 2.4.1
  • MongoDB Java Driver версия 2.11.1
  • JSF версия 2.2
  • PrimeFaces версия 3.5
  • EclipseLink версия 2.4
  • Jetty 7.x Maven Плагин
  • JDK версия 1.7
  • Maven 3.0.4

Зависимости проекта

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.faces</artifactId>
   <version>2.2.0-SNAPSHOT</version>
</dependency>

<dependency>
   <groupId>org.primefaces</groupId>
   <artifactId>primefaces</artifactId>
   <version>3.5</version>
</dependency>

<dependency>
   <groupId>org.primefaces.themes</groupId>
   <artifactId>bootstrap</artifactId>
   <version>1.0.10</version>
</dependency>

<dependency>
   <groupId>org.eclipse.persistence</groupId>
   <artifactId>org.eclipse.persistence.jpa</artifactId>
   <version>2.4.0-SNAPSHOT</version>
</dependency>

<dependency>
   <groupId>org.eclipse.persistence</groupId>
   <artifactId>org.eclipse.persistence.nosql</artifactId>
   <version>2.4.0-SNAPSHOT</version>
</dependency>

<dependency>
   <groupId>jboss</groupId>
   <artifactId>jboss-j2ee</artifactId>
   <version>4.2.2.GA</version>
</dependency>

<dependency>
   <groupId>org.mongodb</groupId>
   <artifactId>mongo-java-driver</artifactId>
   <version>2.11.1</version>
</dependency>

<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3</version>
</dependency>

Класс сущности

@Entity
@NoSql(dataFormat=DataFormatType.MAPPED)
public class Article implements Serializable {

    public Article() { 
    }

    @Id
    @GeneratedValue
    @Field(name="_id")
    private String id;

    @ElementCollection
    private List<Categories> categoryLists = new ArrayList<Categories>();

    @Basic
    private String title;

    @Basic
    private String content;

    @Basic
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date date;

    @Basic
    private String author;

    @ElementCollection
    private List<Tags> tagLists = new ArrayList<Tags>();

Нотация @NoSQL устанавливает формат и тип данных и отображает данные NoSQL. Из-за использования MongoDB в нашем примере приложения и документов в MongoDB, хранящихся в
формате
BSON ,
MAP используется в качестве типа данных.
Нотация
@ElementCollection отображает встроенную коллекцию в родительский документ. Так как в нашем примере приложения было бы более одной категории и тега, связанных со статьей, мы отображаем их как коллекцию элементов.

Встроенные объекты

@Embeddable
@NoSql(dataFormat=DataFormatType.MAPPED)
public class Categories implements Serializable {

    @Basic
    private String category;

@Embeddable
@NoSql(dataFormat=DataFormatType.MAPPED)
public class Tags implements Serializable {

    @Basic
    private String tag;

Мы видим
нотацию
@Embeddable вверху класса
Categories и
Tags в отличие от
класса сущности
Article . Документы, хранящиеся в родительском документе, отображаются в этой записи.
Обратите внимание, что встроенные объекты не нуждаются в уникальном поле.

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="kodcuMongo" transaction-type="RESOURCE_LOCAL">
        <class>com.kodcu.entity.Article</class>
        <class>com.com.kodcu.entity.Categories</class>
        <class>com.kodcu.entity.Tags</class>
        <properties>
            <property name="eclipselink.target-database" 
                              value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
            <property name="eclipselink.nosql.connection-spec" 
                              value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
            <property name="eclipselink.nosql.property.mongo.port" value="27017"/>
            <property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
            <property name="eclipselink.nosql.property.mongo.db" value="kodcu"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>
</persistence>

CRUD Операции 

index.xhtml

<h:form id="articleForm">
            <p:growl id="growl"/>
            <h:panelGrid columns="2" cellpadding="2" cellspacing="2">
                <p:panel styleClass="registrationForm" header="Registration Form">

                    <h:panelGrid id="registrationPanelGrid" columns="2" cellpadding="2" cellspacing="2">
                        <h:outputLabel value="Category"/>
                        <p:inputText value="#{myBean.categories}" styleClass="inputTextWidth"/>

                        <h:outputLabel value="Title"/>
                        <p:inputText value="#{myBean.article.title}" required="#{param['saveArticle']=='true'}" requiredMessage="The title field is required." styleClass="inputTextWidth"/>

                        <h:outputLabel value="Content"/>
                        <p:inputTextarea value="#{myBean.article.content}" required="#{param['saveArticle']=='true'}" requiredMessage="The content field is required." styleClass="inputTextAreaWidthHeight"/>

                        <h:outputLabel value="Author"/>
                        <p:inputText value="#{myBean.article.author}" required="#{param['saveArticle']=='true'}" requiredMessage="The author field is required." styleClass="inputTextWidth"/>

                        <h:outputLabel value="Tags"/>
                        <p:inputText value="#{myBean.tags}" styleClass="inputTextWidth" />

                    </h:panelGrid>
                </p:panel>

                <p:panel header="Article Directory" styleClass="articleDirectory">
                    <p:dataTable id="articleTable" var="article" value="#{myBean.articleList}" selectionMode="single" 
                                 selection="#{myBean.selectArticle}" paginator="true" paginatorPosition="bottom" rows="5"
                                 rowKey="#{article.id}">

                        <p:ajax event="rowSelect" listener="#{myBean.articleSelect}" 
                                update=":articleForm:registrationPanelGrid :articleForm:removeArticle"/>

                        <p:column width="200">
                            <f:facet name="header">
                                <h:outputLabel value="Title"/>
                            </f:facet>
                            <h:outputLabel value="#{article.title}"/>
                        </p:column>

                        <p:column width="350">
                            <f:facet name="header">
                                <h:outputLabel value="Content"/>
                            </f:facet>
                            <h:outputLabel value="#{article.content}"/>
                        </p:column>

                        <p:column width="200">
                            <f:facet name="header">
                                <h:outputLabel value="Author"/>
                            </f:facet>
                            <h:outputLabel value="#{article.author}"/>
                        </p:column>

                        <p:column width="40">
                            <f:facet name="header">
                                <h:outputLabel value="Date"/>
                            </f:facet>
                            <h:outputLabel value="#{article.date}">
                                <f:convertDateTime pattern="dd/MM/yyyy"/>
                            </h:outputLabel>
                        </p:column>

                    </p:dataTable>
                </p:panel>

                <h:panelGroup>
                    <p:commandButton id="newArticle" action="#{myBean.initArticle}" value="New" 
                                     update="registrationPanelGrid articleTable removeArticle"/>
                    <p:commandButton id="saveArticle" action="#{myBean.saveArticle}" value="Save" 
                                     update="registrationPanelGrid articleTable growl">
                        <f:param name="saveArticle" value="true"/>
                    </p:commandButton>
                    <p:commandButton id="removeArticle" disabled="#{null == myBean.selectArticle}" action="#{myBean.removeArticle}" 
                                     value="Remove" update="registrationPanelGrid articleTable @this"/>
                </h:panelGroup>
            </h:panelGrid>

        </h:form>

MyBean.java

public void saveArticle() {

    em.getTransaction().begin();

    if(null == article.getId())
       em.persist(article);
    else
       em.merge(article);

    em.getTransaction().commit();
}

public void removeArticle() {

    em.getTransaction().begin();
    em.remove(selectArticle);
    em.getTransaction().commit();

}

6. Демо-приложение

Реальный контент выше и демонстрационное приложение, могут быть доступны в 
NoSQL с JPA