Java/JPA/Self Join — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
 
м (1 версия)
 
(нет различий)

Текущая версия на 07:22, 1 июня 2010

Join Member Entities

File: Professor.java

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class Professor {
    @Id
    private int id;
    private String name;
    private long salary;
    @Temporal(TemporalType.DATE)
    private Date startDate;
    
    @ManyToOne
    private Professor manager;
    
    @OneToMany(mappedBy="manager")
    private Collection<Professor> directs;
    @ManyToOne
    private Department department;
    
    @ManyToMany 
    private Collection<Project> projects;
    public Professor() {
        projects = new ArrayList<Project>();
        directs = new ArrayList<Professor>();
    }
    public int getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    public long getSalary() {
        return salary;
    }
    public Date getStartDate() {
        return startDate;
    }
    
    public Department getDepartment() {
        return department;
    }
    
    public Collection<Professor> getDirects() {
        return directs;
    }
    
    public Professor getManager() {
        return manager;
    }
    public Collection<Project> getProjects() {
        return projects;
    }
    
    public String toString() {
        return "Professor " + getId() + 
               ": name: " + getName() +
               ", salary: " + getSalary() +
               ", dept: " + ((getDepartment() == null) ? null : getDepartment().getName());
    }
}

File: ProfessorService.java
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
public class ProfessorService {
  protected EntityManager em;
  public ProfessorService(EntityManager em) {
    this.em = em;
  }
  Query unassignedQuery;
  
  public List findProjectProfessors(String projectName) {
    return em.createQuery("SELECT e " +
                          "FROM Project p JOIN p.employees e " +
                          "WHERE p.name = :project " +
                          "ORDER BY e.name")
             .setParameter("project", projectName)
             .getResultList();
}
}

File: Project.java

import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
@Entity
public class Project {
    @Id
    protected int id;
    protected String name;
    @ManyToMany(mappedBy="projects")
    private Collection<Professor> employees;
    public Project() {
        employees = new ArrayList<Professor>();
    }
    public int getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public Collection<Professor> getProfessors() {
        return employees;
    }
    
    public String toString() {
        return "Project id: " + getId() + ", name: " + getName();
    }
}

File: Department.java

import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class Department {
    @Id
    private int id;
    private String name;
    @OneToMany(mappedBy="department")
    private Collection<Professor> employees;
    public Department() {
        employees = new ArrayList<Professor>();
    }
    
    public int getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public Collection<Professor> getProfessors() {
        return employees;
    }
    public String toString() {
        return "Department no: " + getId() + 
               ", name: " + getName();
    }
}

File: JPAUtil.java
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class JPAUtil {
  Statement st;
  
  public JPAUtil() throws Exception{
    Class.forName("org.hsqldb.jdbcDriver");
    System.out.println("Driver Loaded.");
    String url = "jdbc:hsqldb:data/tutorial";
    Connection conn = DriverManager.getConnection(url, "sa", "");
    System.out.println("Got Connection.");
    st = conn.createStatement();
  }
  public void executeSQLCommand(String sql) throws Exception {
    st.executeUpdate(sql);
  }
  public void checkData(String sql) throws Exception {
    ResultSet rs = st.executeQuery(sql);
    ResultSetMetaData metadata = rs.getMetaData();
    for (int i = 0; i < metadata.getColumnCount(); i++) {
      System.out.print("\t"+ metadata.getColumnLabel(i + 1)); 
    }
    System.out.println("\n----------------------------------");
    while (rs.next()) {
      for (int i = 0; i < metadata.getColumnCount(); i++) {
        Object value = rs.getObject(i + 1);
        if (value == null) {
          System.out.print("\t       ");
        } else {
          System.out.print("\t"+value.toString().trim());
        }
      }
      System.out.println("");
    }
  }
}

File: Main.java
import java.util.Collection;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
  public static void main(String[] a) throws Exception {
    JPAUtil util = new JPAUtil();
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("ProfessorService");
    EntityManager em = emf.createEntityManager();
    ProfessorService service = new ProfessorService(em);
    em.getTransaction().begin();
    service.findProjectProfessors("projName");
   
    util.checkData("select * from Professor");
    util.checkData("select * from Department");
    
    em.getTransaction().rumit();
    em.close();
    emf.close();
  }
}


File: persistence.xml
<persistence xmlns="http://java.sun.ru/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.ru/xml/ns/persistence http://java.sun.ru/xml/ns/persistence/persistence" version="1.0">
  <persistence-unit name="JPAService" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.connection.password" value=""/>
      <property name="hibernate.connection.url" value="jdbc:hsqldb:data/tutorial"/>
    </properties>
  </persistence-unit>
</persistence>





Relations on one entity

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
package relations;
import java.util.*;
import javax.persistence.*;
// import the enums for MALE and FEMALE
import static relations.Deity.Gender.*;

/** 
 * A very simple, stand-alone program that stores a new entity in the
 * database and then performs a query to retrieve it.
 */
public class Main {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        // Create a new EntityManagerFactory using the System properties.
        // The "relations" name will be used to configure based on the
        // corresponding name in the META-INF/persistence.xml file
        EntityManagerFactory factory = Persistence.
            createEntityManagerFactory("relations", System.getProperties());
        // Create a new EntityManager from the EntityManagerFactory. The
        // EntityManager is the main object in the persistence API, and is
        // used to create, delete, and query objects, as well as access
        // the current transaction
        EntityManager em = factory.createEntityManager();
        initFamilyTree(em);
        runQueries(em);
        // It is always good to clean up after ourselves
        em.close();
        factory.close();
    }
    /** 
     * Creates a partial family tree of the Greek dieties.
     *  
     * @param  em  the EntityManager to use in the persistence process
     */
    public static void initFamilyTree(EntityManager em) {
        // First delete all the members from the database the clean up
        em.getTransaction().begin();
        em.createQuery("delete from Deity").executeUpdate();
        em.getTransaction().rumit();
        // Generation 1
        Deity uranus = new Deity("Uranus", MALE);
        Deity gaea = new Deity("Gaea", FEMALE);
        // Generation 2
        Deity cronus = gaea.giveBirth("Cronus", uranus, MALE);
        Deity rhea = gaea.giveBirth("Rhea", uranus, FEMALE);
        Deity coeus = gaea.giveBirth("Coeus", uranus, MALE);
        Deity phoebe  = gaea.giveBirth("Phoebe", uranus, FEMALE);
        Deity oceanus = gaea.giveBirth("Oceanus", uranus, MALE);
        Deity tethys = gaea.giveBirth("Tethys", uranus, FEMALE);
        // Generation 3
        Deity leto = phoebe.giveBirth("Leto", coeus, FEMALE);
        Deity hestia = rhea.giveBirth("Hestia", cronus, FEMALE);
        Deity pluto = rhea.giveBirth("Pluto", cronus, MALE);
        Deity poseidon = rhea.giveBirth("Poseidon", cronus, MALE);
        Deity zeus = rhea.giveBirth("Zeus", cronus, MALE);
        Deity hera = rhea.giveBirth("Hera", cronus, FEMALE);
        Deity demeter = rhea.giveBirth("Demeter", cronus, FEMALE);
        // Generation 4
        Deity iapetus = tethys.giveBirth("Iapetus", coeus, MALE);
        Deity clymene = new Deity("Clymene", FEMALE);
        Deity apollo = leto.giveBirth("Apollo", zeus, MALE);
        Deity artemis = leto.giveBirth("Artemis", zeus, MALE);
        Deity persephone = demeter.giveBirth("Persephone", zeus, MALE);
        Deity ares = hera.giveBirth("Ares", zeus, MALE);
        Deity hebe = hera.giveBirth("Hebe", zeus, FEMALE);
        Deity hephaestus = hera.giveBirth("Hephaestus", zeus, MALE);
        Deity prometheus = clymene.giveBirth("Prometheus", iapetus, MALE);
        Deity atlas = clymene.giveBirth("Atlas", iapetus, MALE);
        Deity epimetheus = clymene.giveBirth("Epimetheus", iapetus, FEMALE);
        Deity dione = new Deity("Dione", FEMALE);
        dione.giveBirth("Aphrodite", zeus, FEMALE);
        // Begin a new local transaction so that we can persist a new entity
        em.getTransaction().begin();
        // note that we only need to explicitly persist a single root of the
        // object graph (the family tree, in this case), since we have the
        // "cascade" annotation on all the relations
        em.persist(zeus);
        // Commit the transaction, which will cause the entity to
        // be stored in the database
        em.getTransaction().rumit();
    }
    /** 
     * Run some sample queries against the family tree model.
     *  
     * @param  em  the EntityManager to use
     */
    public static void runQueries(EntityManager em) {
        System.out.println("Running query to find all instances..");
        // Perform a simple query for all the Deity entities
        Query q = em.createQuery("select x from Deity x");
        // Go through each of the entities and print out each of their
        // messages, as well as the date on which it was created 
        for (Deity m : (List<Deity>) q.getResultList()) {
            System.out.println(m.getName());
        }
        q = em.createQuery("select x from Deity x "
            + "where x.father.name = "Zeus"");
        for (Deity m : (List<Deity>) q.getResultList()) {
            System.out.println("Child of Zeus: " + m.getName());
        }
        q = em.createNamedQuery("siblings").
            setParameter(1, em.getReference(Deity.class, "Rhea"));
        for (Deity m : (List<Deity>) em.createNamedQuery("siblings").
            setParameter(1, em.getReference(Deity.class, "Rhea")).
            getResultList()) {
            System.out.println("Siblings of Rhea: " + m.getName());
        }
        for (Deity m : (List<Deity>) em.createNamedQuery("half-siblings").
            setParameter(1, em.getReference(Deity.class, "Apollo")).
            getResultList()) {
            System.out.println("Half-siblings of Apollo: " + m.getName());
        }
        for (Deity m : (List<Deity>) em.createNamedQuery("cousins").
            setParameter(1, em.getReference(Deity.class, "Leto")).
            getResultList()) {
            System.out.println("Cousins of Leto: " + m.getName());
        }
    }
}
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
package relations;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.EnumType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.NamedQueries;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

/** 
 * An entity that contains relations corresponding to family tree relations.
 * This entity demonstrates the following JPA features:
 *
 * 1. Enum fields (gender)
 * 2. @OneToOne relations
 * 3. @OneToMany relations
 * 4. Named queries
 */
@Entity
@NamedQueries({
    // a sibling shares a mother and a father
    @NamedQuery(name="siblings", query="select distinct sibling1 "
        + "from Deity sibling1, Deity sibling2 where "
        + "sibling1.father = sibling2.father "
        + "and sibling1.mother = sibling2.mother "
        + "and sibling2 = ?1 and sibling1 <> ?1"),
    // a half-siling shares a mother or a father, but not both
    @NamedQuery(name="half-siblings", query="select distinct sibling1 "
        + "from Deity sibling1, Deity sibling2 where "
        + "((sibling1.father = sibling2.father "
        + "and sibling1.mother <> sibling2.mother) "
        + "or (sibling1.father <> sibling2.father "
        + "and sibling1.mother = sibling2.mother)) "
        + "and sibling2 = ?1 and sibling1 <> ?1"),
    // a cousin shares a grandparent, but is not a sibling
    @NamedQuery(name="cousins", query="select distinct cousin1 "
        + "from Deity cousin1, Deity cousin2 where "
        + "("
            + "cousin1.father.father = cousin2.father.father "
            + "or cousin1.father.mother = cousin2.father.mother "
            + "or cousin1.mother.father = cousin2.mother.father "
            + "or cousin1.mother.mother = cousin2.mother.mother) "
        + "and (cousin1.father <> cousin2.father) "
        + "and (cousin1.mother <> cousin2.mother) "
        + "and cousin2 = ?1 and cousin1 <> ?1")
    })
public class Deity implements Serializable {
    // the Id is the name, which is generally a bad idea, but we are
    // confident that diety names will be unique
    @Id
    private String name;
    @Basic @Enumerated(EnumType.STRING)
    private Gender gender;
    @OneToOne(cascade=CascadeType.ALL)
    private Deity mother;
    @OneToOne(cascade=CascadeType.ALL)
    private Deity father;
    @OneToMany(cascade=CascadeType.ALL)
    private Set<Deity> children;
    public static enum Gender { MALE, FEMALE }

    public Deity(String name, Gender gender) {
        this.name = name;
        this.gender = gender;
    }

    //////////////////////////
    // Business methods follow
    //////////////////////////
    /** 
     * She"s having a baby... 
     *  
     * @param  childName  the baby name
     * @return the new child
     *
     * @throws IllegalArgumentException if the person is not a woman, or
     *                                  if the person is unmarried (illegitimate
     *                                  children are not yet supported)
     */
    public Deity giveBirth(String childName, Deity childFather, Gender gender) {
        if (this.gender != Gender.FEMALE)
            throw new IllegalArgumentException("Only women can have children!");
        if (childName == null)
            throw new IllegalArgumentException("No child name!");
        // create the child
        Deity child = new Deity(childName, gender);
        // set the parents in the children...
        child.mother = this;
        // add the child to this member"s children
        if (children == null)
            children = new HashSet<Deity>();
        children.add(child);
        if (childFather != null) {
            child.father = childFather;
            if (childFather.children == null)
                childFather.children = new HashSet<Deity>();
            childFather.children.add(child);
        }
        return child;
    }

    ////////////////////////////////////
    // Property accessor methods follow
    ////////////////////////////////////

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }
    public Gender getGender() {
        return this.gender;
    }

    public void setMother(Deity mother) {
        this.mother = mother;
    }
    public Deity getMother() {
        return this.mother;
    }

    public void setFather(Deity father) {
        this.father = father;
    }
    public Deity getFather() {
        return this.father;
    }

    public void setChildren(Set<Deity> children) {
        this.children = children;
    }
    public Set<Deity> getChildren() {
        return this.children;
    }
}