<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Chan Chen Coding...

    Understand JPA

    Need three artifacts to implement a JPA-compliant program:

    • An entity class
    • A persistence.xml file
    • A class through which you will insert, update, or find an entity

    JPA is all about data persistence, so let's begin our examination of how it works with the data store design. Assume you have a CUSTOMER table, as in Table 1 below.

    Table 1. CUSTOMER table schema

    NAMEPK?TYPENULL?
    CUST_ID Y INTEGER NOT NULL
    FIRST_NAME   VARCHAR(50) NOT NULL
    LAST_NAME   VARCHAR(50)  
    STREET   VARCHAR(50)  
    APPT   VARCHAR(20) NOT NULL
    CITY   VARCHAR(25)  
    ZIP_CODE   VARCHAR(10) NOT NULL
    CUST_TYPE   VARCHAR(10) NOT NULL
    LAST_UPDATED_TIME   TIMESTAMP NOT NULL

    The persistence object: Entity

    Since JPA is all about entity-relationship mapping, next you need to take a look at the design of the Customer entity object. The entity object is nothing but a POJO class marked as an entity with the@Entity annotation, as you can see in Listing 1.

    Listing 1. The Customer entity

    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.Date;

    @Entity(name = "CUSTOMER") //Name of the entity
    public class Customer implements Serializable{
        private long custId;
        private String firstName;
        private String lastName;
        private String street;
        private String appt;
        private String city;    
        private String zipCode;
        private String custType;
        private Date updatedTime;

    // Getters and setters go here 
    .
    }

    The Customer entity needs to know how to map the attributes (or properties) to the CUSTOMER table. You can do this either through a configuration file called orm.xml (similar to a .hbm file in Hibernate) or, as shown in Listing 2, through JPA annotations.

    Listing 2. The Customer entity with annotations

    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.Date;

    @Entity(name = "CUSTOMER") //Name of the entity
    public class Customer implements Serializable{
        @Id //signifies the primary key
        @Column(name = "CUST_ID", nullable = false)
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long custId;
        
        @Column(name = "FIRST_NAME", nullable = false,length = 50)
        private String firstName;
        
        @Column(name = "LAST_NAME", length = 50)
        private String lastName;
        
    // By default column name is same as attribute name
        private String street;
        
        @Column(name = "APPT",nullable = false)  
        private String appt;
        
        // By default column name is same as attribute name
        private String city;
        
        @Column(name = "ZIP_CODE",nullable = false)  
        // Name of the corresponding database column
        private String zipCode;
        
        @Column(name = "CUST_TYPE", length = 10)
        private String custType;

        @Version
        @Column(name = "LAST_UPDATED_TIME")
        private Date updatedTime;

    // Getters and setters go here 
    .
    }

    Take a closer look at the annotations defined in Listing 2.

    • The annotations are defined in javax.persistence, so you'll need to import that package.
    • @Enitity signifies that a particular class is an entity class. If the entity name is different from the table name, then the @Table annotation is used; otherwise, it isn't required.
    • @Column provides the name of the column in a table if it is different from the attribute name. (By default, the two names are assumed to be the same.)
    • @Id signifies the primary key.
    • @Version signifies a version field in an entity. JPA uses a version field to detect concurrent modifications to a data store record. When the JPA runtime detects multiple attempts to concurrently modify the same record, it throws an exception to the transaction attempting to commit last. This prevents you from overwriting the previous commit with stale data.
    • By default, all the fields are of type @Basic, which are persisted as-is in the database.
    • @GeneratedValue signifies a strategy to assign a unique value to your identity fields automatically. The types of strategies available are IDENTITY, SEQUENCE, TABLE, and AUTO. The default strategy is auto, the implementation of which is left to the JPA vendor to implement. (OpenJPA implements it through a table sequence.)

    There are a few points to keep in mind when creating an entity class:

    • JPA allows persistent classes to inherit from non-persistent classes, persistent classes to inherit from other persistent classes, and non-persistent classes to inherit from persistent classes.
    • The entity class should have a default no-argument constructor.
    • The entity class should not be final.
    • Persistent classes cannot inherit from certain natively-implemented system classes such as java.net.Socket and java.lang.Thread.
    • If a persistent class inherits from a non-persistent class, the fields of the non-persistent super class cannot be persisted.

    Persistence units

    Now that the entity class is complete, you can move on to persistence.xml, shown in Listing 3. This is an XML file placed in the META-INF folder; it's used to specify the persistence provider name, entity class names, and properties like the database connection URL, driver, user, password, and so on.

    Listing 3. A sample persistence.xml file

    <?xml version="1.0"?>
    <persistence>
        <persistence-unit name="testjpa" transaction-type="RESOURCE_LOCAL">
            <provider>
                org.apache.openjpa.persistence.PersistenceProviderImpl
            </provider>
            <class>entity.Customer</class>
            <properties>
                <property name="openjpa.ConnectionURL"          value="jdbc:derby://localhost:1527/D:\OpenJPA\Derby\testdb;create=true"/>
                <property name="openjpa.ConnectionDriverName" 
                value="org.apache.derby.jdbc.ClientDriver"/>
                <property name="openjpa.ConnectionUserName" value="admin"/>
                <property name="openjpa.ConnectionPassword" value="admin"/>
        <property name="openjpa.Log" value="SQL=TRACE"/>
            </properties>
        </persistence-unit>
    </persistence>

    Some important things to note about Listing 3 and the persistence.xml file:

    • persistence.xml can have multiple persistence units. Each unit can be used by different JPA vendor or can be used to persist to different databases.
    • The vendor-specific persistence provider name is specified in the<provider> tag. The persistence provider for OpenJPA isorg.apache.openjpa.persistence.PersistenceProviderImpl.
    • The entity class names are specified in the <class> tag.
    • The database connection properties can be specified within the<properties> tag. Note that the property name will differ for each vendor.
    • OpenJPA has its own default logging facility, the default level of which is INFO.

    The real show

    Now that the prep work is out of the way, you're ready to write a class that will insert a record into the CUSTOMER table. This is shown in Listing 4.

    Listing 4. sample code for object persistence

    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory =  Persistence.createEntityManagerFactory("testjpa");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction userTransaction = em.getTransaction();
        
        userTransaction.begin();
        Customer customer = new Customer();
        customer.setFirstName("Charles");
        customer.setLastName("Dickens");
        customer.setCustType("RETAIL");
        customer.setStreet("10 Downing Street");
        customer.setAppt("1");
        customer.setCity("NewYork");
        customer.setZipCode("12345");
        em.persist(customer);
        userTransaction.commit();
        em.close();
        entityManagerFactory.close();
    }

    Drill down to see what the code in Listing 4 actually does. The action starts with the Persistence class. The javadoc says, "Persistence is a bootstrap class that is used to obtain an EntityManagerFactory," like so:
    EntityManagerFactory emf=Persistence.createEntityManagerFactory("testjpa");

    The work of the Persistence class is pretty simple:

    • In the classpath resources, the Persistence class searches for javax.persistence.spi.PersistenceProvider files in META-INF/services/directory. It reads the PersistenceProvider implementation class names from each file.
    • It then calls createEntityManagerFactory() on each PersistenceProvider with the persistenceUnitName until it gets a anEntityManagerFactory back that isn't null. The provider name for OpenJPA is org.apache.openjpa.persistence.PersistenceProviderImpl.

    How does PersistenceProvider get the right EntityManagerFactory? This is up to the vendor to implement.

    EntityManagerFactory is a factory for creating an EntityManagerEntityManagerFactory should be cached and should ideally be called once for each persistence unit name in the whole application.

    EntityManager manages entities; it is responsible for their addition, updating, and deletion. You can find an entity without a transaction; however, add, update, and delete operations need to be within a transaction.

    If you ignore transaction management in a fetch operation, the entity does not become managed and hence the system will do a trip to the database every time you try to fetch a record from the data store; in such a scenario, you'd end up fetching a separate object every time.

    The rest of the code is pretty self-explanatory. It creates a customer object, sets the values to the appropriate properties, and inserts the object to the data store, as you can see in Listing 5.

    Listing 5. A code snippet for object persistence

    EntityTransaction userTransaction = em.getTransaction();
        userTransaction.begin();
        em.persist(customer);
        userTransaction.commit();

    You may have already noticed by now that the code does not set the custId and updatedTime to the customer object explicitly. Because the primary key generation strategy is AUTO, the JPA provider will take care of populating the primary key. Similarly, version fields (updatedTime, in this case) are also automatically populated by the JPA provider.

    Now you need to find the record that's been inserted. Finding a record with a primary key is as simple as Customer cust = em.find(Customer.class, objId);, as you can see in Listing 6.

    Listing 6. Fetching data as an object

    .
    OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
    Object objId = oem.getObjectId(customer);
    Customer cust = em.find(Customer.class, objId);
    .

    A composite primary key

    Now, how do you find a record in the database with a primary key if the entity has a composite primary key? You'll see how that works in a moment. Assume that the CUSTOMER table doesn't have aCUST_ID field, but that FIRST_NAME and LAST_NAME together make up the primary key. To make this work, you need to create a separate class, generally called an identity class, with attributes the same as the IDs; then you reference the identity class in the entity class. This is shown in Listing 7.

    Listing 7. An identity class

    public class CustomerId {
        public String firstName;
        public String lastName;
        // override equal() method
        
    //override hascode() method

    }

    The identity class can be a separate class or an inner class. If the class is an inner class, it must be static and should be referenced in the entity class, as in Listing 8. The code for finding records with a composite primary key is exactly the same as that for finding records with a single primary key.

    Listing 8. Using an identity class

    @Entity
    @IdClass(Customer.CustomerId.class)
    public class Customer implements Serializable{
        @Id
        @Column(name = "FIRST_NAME", nullable = false, length = 50)
        private String firstName;

        @Id
        @Column(name = "LAST_NAME", length = 50)
        private String lastName;

        private String street;

        @Column(name = "APPT",nullable = false)  
        private String appt;
        
    .
    }


    The callbacks

    JPA provides callback methods for performing actions at different stages of persistence operations. Imagine that you want to update a customer record, but, before you update, you want to remove the hyphen from the zip code if one is present. Or say that you want to populate some transient fields after a successful fetch. JPA provides listeners for these kinds of activities before and after each fetch, insert, or update operation. The callback methods can be annotated as any of the following:

    • @PostLoad
    • @PrePersist
    • @PostPersist
    • @PreUpdate
    • @PostUpdate
    • @PreRemove
    • @PostRemove

    You can write the callback methods in the entity class itself, or you can write them in a separate class and reference them in the entity class with @EntityListeners, as shown in Listing 9.

    Listing 9. implementing callback

    @EntityListeners({CustListner.class})
    @Entity(name = "CUSTOMER") //Name of the entity
    public class Customer implements Serializable{


    }
    public class CustListner {
        @PreUpdate
        public void preUpdate(Customer cust) {
             System.out.println("In pre update");
        }
        @PostUpdate
        public void postUpdate(Customer cust) {
             System.out.println("In post update");
        }
    }

    Embedded objects

    As you've seen so far, the Customer entity has the address information inline in the entity itself. What if you want to apply class normalization concepts and come up with a separate Address class and refer to that in the Customer entity? After all, an address object could be used with CustomerEmployeeOrder, or User entities.

    All you need is an embedded object. You move the address information into a separate class and mark that class as being embeddable, as shown in Listing 10. Refer to this newly created class from the Customer entity with @Embedded annotations.

    Listing 10. An embeddable class

    @Embeddable
    public class Address implements Serializable{
        
        private String street;
        
        @Column(name = "APPT",nullable = false)  
        private String appt;

        private String city;
    ..
    ..
    }

    Embedded classes are mapped together with their owning entity as part of the state of that entity. However, they cannot be queried separately. Listing 11 illustrates a sample entity that uses an embedded object.

    Listing 11. A sample entity using an embedded object

    @Entity
    public class Customer {

        @Column(name = "FIRST_NAME", nullable = false,length = 50)
        private String firstName;
            
        @Embedded
        private Address address;
    ..
    }

    The power of inheritance

    An entity can extend the following:

    • Another entity -- either concrete or abstract.
    • Another non-entity, supplying behavior or non-persistence state. The attributes you inherit from a non-entity are not persisted.
    • Mapped superclasses, supplying common entity state. Tables in a database have similar fields, but tables are not related to each other.

    Let's have a look into the various types of inheritance JPA offers. For this scenario, assume that there are two types of customer: a normal customer who buys products from a physical store and an online customer who buys products over the Internet.

    Single-table inheritance

    In single-table inheritance, all the entities in the hierarchy are stored in a single table. Single-table inheritance is the default strategy. Thus, you could omit the @Inheritance annotation in the example code in Listing 12 and get the same result.

    In the example application, both ordinary and online customers are stored in the CUSTOMER table, as shown in Table 2.

    Table 2. Single-table inheritance mapping strategy

    ENTITYTABLE NAME
    Customer CUSTOMER
    OnlineCustomer CUSTOMER

    The Customer entity has custIdfirstNamelastNamecustType, and address information, whereas the OnlineCustomer entity has only awebsite attribute and otherwise extends all features of Customer. This strategy should be reflected in the superclass, as in Listing 12.

    Listing 12. A sample superclass in single-table inheritance

    @Entity(name = "CUSTOMER") 
    @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name="CUST_TYPE", discriminatorType=DiscriminatorType.STRING,length=10)
    @DiscriminatorValue("RETAIL")
    public class Customer implements Serializable{
        @Id 
        @Column(name = "CUST_ID", nullable = false)
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long custId;
        
        @Column(name = "FIRST_NAME", nullable = false,length = 50)
        private String firstName;
        
        @Column(name = "LAST_NAME", length = 50)
        private String lastName;
        
        @Embedded
        private Address address = new Address();
        
        @Column(name = "CUST_TYPE", length = 10)
        private String custType;
    .
    }

    For the time being, ignore the DiscriminatorColumn and DiscriminatorValue annotations; you'll see how those work later. TheOnlineCustomer entity will be a normal entity class that extends Customer class, as shown in Listing 13.

    Listing 13. A sample subclass in single-table inheritance

    @Entity(name = "ONLINECUSTOMER") //Name of the entity
    @DiscriminatorValue("ONLINE")
    public class OnlineCustomer extends Customer{
        @Column(name = "WEBSITE", length = 100)
        private String website;
        
    }

    Now you must create a Customer object and an OnlineCustomer object and persist them, as in Listing 14.

    Listing 14. Persisting objects in single-table inheritance

    .
    userTransaction.begin();
    //inserting Customer
    Customer customer = new Customer();
    customer.setFirstName("Charles");
    customer.setLastName("Dickens");
    customer.setCustType("RETAIL");
    customer.getAddress().setStreet("10 Downing Street");
    customer.getAddress().setAppt("1");
    customer.getAddress().setCity("NewYork");
    customer.getAddress().setZipCode("12345");
    em.persist(customer);
    //Inserting Online customer
    OnlineCustomer onlineCust = new OnlineCustomer();
    onlineCust.setFirstName("Henry");
    onlineCust.setLastName("Ho");
    onlineCust.setCustType("ONLINE");
    onlineCust.getAddress().setStreet("1 Mission Street");
    onlineCust.getAddress().setAppt("111");
    onlineCust.getAddress().setCity("NewYork");
    onlineCust.getAddress().setZipCode("23456");
    onlineCust.setWebsite("www.amazon.com");
    em.persist(onlineCust);
    userTransaction.commit();
    .

    If you have a look into the CUSTOMER table now, you will find two records. The query in Listing 15 should return you the list of online customers from the data store.

    Listing 15. Fetching only the subclass in single-table inheritance

    ..
    Query query = em.createQuery("SELECT customer FROM ONLINECUSTOMER customer");
    List<OnlineCustomer> list= query.getResultList();
    ..

    If the CUSTOMER table stores both the Customer and the OnlineCustomer data, how will JPA distinguish one from the other? How will it fetch only the online customers? In fact, JPA cannot do this unless you provide it with a hint. That's the significance of the @DiscriminatorColumn. It tells the CUSTOMER table which column distinguishes a CUSTOMER from an ONLINE CUSTOMER. @DiscriminatorValue indicates what value identifies a CUSTOMER and an ONLINE CUSTOMER. The@DiscriminatorValue annotation needs to be provided in the superclass as well as in all the subclasses.

    When you want to fetch online customers, JPA silently queries the data store as in Listing 16.

    Listing 16. Distinguishing objects stored in a single table

    SELECT t0.CUST_ID, t0.CUST_TYPE, t0.LAST_UPDATED_TIME, t0.APPT, t0.city, t0.street, t0.ZIP_CODE, t0.FIRST_NAME, t0.LAST_NAME, t0.WEBSITE FROM CUSTOMER t0 
    WHERE t0.CUST_TYPE = 'ONLINE'

    Joined-table inheritance

    In the joined-table inheritance strategy, the common states of the class are stored in one table, and the state of the subclass is stored in another table that is joined to the first table, as shown in Table 3.

    Table 3. Joined-table inheritance mapping strategy

    ENTITYTABLE NAME
    Customer CUSTOMER
    OnlineCustomer ONLINECUSTOMER (only Website information is stored here; the rest of the information is stored in the CUSTOMER table)

    The common data that the OnlineCustomer entity shares with Customeris stored in the CUSTOMER table; OnlineCustomer-specific data is stored in the ONLINECUSTOMER table, connected by a foreign key constraint. From the JPA implementation standpoint, the only change needed in the OnlineCustomer entity is that the JOINED strategy must be provided, as in Listing 17.

    Listing 17. A superclass in joined-table inheritance

    @Entity(name = "CUSTOMER") //Name of the entity
    @Inheritance(strategy=InheritanceType.JOINED)
    @DiscriminatorColumn(name="CUST_TYPE", discriminatorType=DiscriminatorType.STRING,length=10)
    @DiscriminatorValue("RETAIL")

    public class Customer implements Serializable{
        @Id //signifies the primary key
        @Column(name = "CUST_ID", nullable = false)
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long custId;
        
        @Column(name = "FIRST_NAME", nullable = false,length = 50)
        private String firstName;
        
        @Column(name = "LAST_NAME", length = 50)
        private String lastName;
        
        @Embedded
        private Address address = new Address();
        
        @Column(name = "CUST_TYPE", length = 10)
        private String custType;
        ..
    }

    In the OnlineCustomer entity, shown in Listing 18, you specify the subclass-specific attributes and a foreign key join column with the@PrimaryKeyJoinColumn annotation, which maps to the primary key of the parent table.

    Listing 18. A sample subclass in joined-table inheritance

    @Table(name="ONLINECUSTOMER")
    @Entity(name = "ONLINECUSTOMER") //Name of the entity
    @DiscriminatorValue("ONLINE")
    @PrimaryKeyJoinColumn(name="CUST_ID",referencedColumnName="CUST_ID")
    public class OnlineCustomer extends Customer{

        @Column(name = "WEBSITE", length = 100)
        private String website;
        .
    }

    In Listing 18, the name property of @PrimaryKeyJoinColumn denotes the primary key of the subclass table. referencedColumnNamedenotes the name of the superclass table column to which this subclass table column joins. Nothing changes in the way in which you persist and fetch the Customer and OnlineCustomer objects.

    Table per class inheritance

    In the table per class inheritance strategy, each class state in a hierarchy is stored in a separate table, as illustrated in Table 4.

    Table 4. Table per class inheritance mapping strategy

    ENTITYTABLE NAME
    Customer CUSTOMER
    OnlineCustomer ONLINECUSTOMER

    You don't need to provide the @DiscriminatorColumn annotation here, as the entities are stored in separate tables altogether. Also, no @PrimaryKeyJoinColumn annotation is required, as no relationship exists between subclass and superclass tables. TheCustomer superclass will look like Listing 19.

    Listing 19. A sample superclass in table per class inheritance

    @Entity(name = "CUSTOMER")
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public class Customer implements Serializable{
        @Id //signifies the primary key
        @Column(name = "CUST_ID", nullable = false)
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long custId;
        
        @Column(name = "FIRST_NAME", nullable = false,length = 50)
        private String firstName;
        
        @Column(name = "LAST_NAME", length = 50)
        private String lastName;
        
        @Embedded
        private Address address = new Address();
        ..
    }


    OnlineCustomer will be like a normal subclass, as shown in Listing 20. Nothing changes in the way in which you persist and fetch the Customer and OnlineCustomer objects.

    Listing 20. A sample subclass in table per class inheritance

    @Entity(name = "ONLINECUSTOMER") //Name of the entity
    public class OnlineCustomer extends Customer{
            
        @Column(name = "WEBSITE", length = 100)
        private String website;
        ..
    }

    Toward a more object-oriented world

    In this first half of "Understanding the Java Persistence API," you saw how you can apply object-oriented concepts like inheritance and event callbacks using JPA. The object-oriented possibilities in JPA go far beyond what has been covered in this article: JPA also lets you write JPQL queries (similar to Hibernate's HQL queries) or native SQL queries, and has transaction management facilities.

    In the second half of this article, you'll have the opportunity to explore data relationships the JPA way -- that is, with object-oriented grace. Look for that article next week. In the meantime, have fun on your own, exploring JPA's object-oriented paradigm of data persistence!

    About the author

    Aditi Das is a technical architect with Infosys Technologies and has seven years of specialized experience in Java and JEE. She is a Sun-certified enterprise architect (SCEA), Web component developer (SCWCD), business component developer (SCBCD), and Web service developer (SCDJWS). She is very much inspired by the Head First philosophy of learning new technologies, and hopes that someday a book will come out on the past, present, and future of SOA.

     



    -----------------------------------------------------
    Silence, the way to avoid many problems;
    Smile, the way to solve many problems;

    posted on 2012-12-24 17:12 Chan Chen 閱讀(489) 評論(0)  編輯  收藏 所屬分類: Scala / Java

    主站蜘蛛池模板: 免费人成再在线观看网站| 国产成人亚洲综合网站不卡| 国产精品极品美女自在线观看免费| 国产美女精品久久久久久久免费| 2020久久精品亚洲热综合一本| 97人妻无码一区二区精品免费| 亚洲成人福利在线观看| 免费可以看黄的视频s色| 亚洲第一男人天堂| 国产精品免费看久久久久| 一边摸一边桶一边脱免费视频| 亚洲伊人久久综合中文成人网| 久久久久久毛片免费看| 91精品国产亚洲爽啪在线观看| 无码中文在线二区免费| 亚洲avav天堂av在线网毛片| 亚洲视频在线免费| 亚洲视频在线免费观看| 亚洲一卡2卡3卡4卡国产网站| 在线播放高清国语自产拍免费| 特级aaaaaaaaa毛片免费视频| 亚洲色大成网站WWW久久九九| 99久久国产免费-99久久国产免费| 亚洲中文字幕人成乱码| 国产成人免费a在线资源| 国产免费久久精品丫丫| 亚洲精品无码99在线观看| 国产日韩AV免费无码一区二区 | 亚洲精品无码久久久| 国产成人无码免费看片软件| 亚洲日本一区二区三区| 毛片免费视频观看| 人体大胆做受免费视频| 亚洲天天在线日亚洲洲精| 日韩高清在线免费观看| 免费av片在线观看网站| 亚洲熟妇AV日韩熟妇在线| 精品久久香蕉国产线看观看亚洲| 无码免费午夜福利片在线 | gogo免费在线观看| 亚洲人成网址在线观看|