• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
03 Object Relational Mapping
 

03 Object Relational Mapping

on

  • 1,190 views

 

Statistics

Views

Total Views
1,190
Views on SlideShare
1,116
Embed Views
74

Actions

Likes
0
Downloads
2
Comments
0

4 Embeds 74

http://ranjankumar.in 65
http://www.slideshare.net 6
http://interopy.wordpress.com 2
http://www.health.medicbd.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    03 Object Relational Mapping 03 Object Relational Mapping Presentation Transcript

    • Object/Relational Mapping Solving the structural paradigm mismatch
    • Creating a Domain Model
      • An object-oriented domain model
        • captures the entities with the help of the business experts
        • concrete things like User, Item, Category, abstract like PricingAlgorithm
        • developers create an object model of the problem domain
        • can be only a mental model or elaborate as UML diagrams
        • we may also have a relational data model, designed using E / R modelling
        • a relational schema, or a model defined in some CASE tool
      Item 0..* User 0..* sells Category
    • Our example application
      • CaveatEmptor is an online auction system – we have the following domain model:
      • Do we need any special programming model to implement this domain model in Java?
      Item 0..* User 0..* sells Bid 0..* 0..* Address 0..* BillingDetails CreditCard BankAccount home billing 0..* Category
    • Writing POJOs
      • We implement our domain model persistent classes with POJOs
        • loosely follow the JavaBean specification (actually, just about any Java class will do)
        • we usually provide accessor methods for property management with (any visibility), but this is not required
        • no-argument constructor (with at least package visibility) is required
        • better to make the class and all public methods non-final
        • declare the class Serializable if you need to transport data between tiers
      POJO Best Practices are actually requirements of Hibernate for persistent classes.
    • A simple POJO public class User implements Serializable { private String username; private Address address; public User() {} public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Address getAddress() { return address;} public void setAddress(Address address) { this.address = address; } public MonetaryAmount calcShippingCosts(Address from) { ... } }
    • Adding logic to accessor methods
      • We can also add certain kinds of logic - especially validation - to our accessor methods:
      • Let’s create the mapping for User ...
      public class User { private String firstname; ... public void setFirstname(String firstname) throws InvalidNameException { if ( !StringUtil.isCapitalizedName(firstname) ) throw new InvalidNameException(firstname); this.firstname = firstname; ) ... }
    • Class mapping
      • We use the <class> element for each persistent class
        • requires class name, table and schema are optional
        • by default, all columns are inserted and updated
        • override with dynamic insert and update, no SQL generation on startup
      <hibernate-mapping package=&quot;org.hibernate.auction.model&quot; schema=&quot;AUCTION&quot;> <class name=&quot;User&quot; table=&quot;USER&quot; dynamic-insert=&quot;true&quot; dynamic-update=&quot;true&quot;> </class> ... </hibernate-mapping>
    • Property mapping
      • We use <property> for each property of our class:
      • If your property and class names are special (prefix, suffix, etc.), implement a Hibernate NamingStrategy .
      <!- An immutable property --> <property name=&quot;orderNumber&quot; column=&quot;ORDER_NR&quot; type=&quot;string&quot; not-null=&quot;true&quot; access=&quot;field&quot; update=&quot;false&quot;/> <!-- A derived property (read only) --> <property name=&quot;totalIncludingTax&quot; formula=”PRICE + PRICE * TAX_RATE&quot; type=&quot;big_decimal&quot;/>
    • Writing persistent classes
      • Entity associations are also represented as properties:
      0..* public class Category { private String name; private Category parentCategory ; private Set childCategories = new HashSet(); Set getChildCategories() { return childCategories; } void setChildCategories(Set categories) { childCategories = categories; } public Category getParentCategory() { return parentCategory(); } void setParentCategory(Category category) { parentCategory = category; } } Category
    • Optimizing association handling
      • To create an association, we have to
        • set the parentCategory of a child
        • the child must be added to the childCategories of the parent
        • we don't have some container-managed relationship handling!
      • We will come back to association mappings soon….
      public void addChildCategory(Category child) { // Be defensive! if (child == null) throw new IllegalArgumentException(&quot;null Child&quot;); // Ensure multiplicity if ( child.getParent() != null ) child.getParent().getChildCategories().remove(child); child.setParent(this); getChildCategories().add(child); }
    • Primary keys
      • The primary key for our tables should be
        • unique: no duplicate values ever
        • constant: value is never updated
        • required: never null
      • Types of primary keys:
        • natural key: an attribute that is unique by virtue of its business meaning (any composite key is a natural key)
        • surrogate key: an attribute generated by the system, with no meaning to the user, and no business semantics
      • For new systems, we recommend the use of surrogate keys everywhere , since this strategy makes schema evolution simpler – true natural keys are hard to find!
    • Database identity in Hibernate
      • We add an identifier property to persistent classes
        • the value of that property is the primary key value
        • the name should always be the same for all classes, e.g. id
      • Should the identifier property be public?
        • if we use the identifier outside of persistence, e.g. in web applications
        • it is a convenient “handle” to a particular instance
        • lookup by identifier is an especially efficient operation in Hibernate
        • we usually have a public getter and a private setter
      public class Category { private Long id = null; public Long getId() { return this.id; } private void setId(Long id) { this.id = id; } }
    • Identity mapping
      • Identifier property mappings
        • the identifier property type may be any Hibernate type
        • the identifier generation strategy may be customized
        • identifier properties are actually optional, but strongly recommended (if you don’t have an identifier property, just omit name in the mapping)
      <class name=&quot;Category&quot; table=&quot;CATEGORY&quot;> <id name=&quot;id&quot; column=&quot;CATEGORY_ID&quot; type=&quot; long &quot;> <generator class=&quot; native &quot;/> </id> ... </class>
    • Identifier generation strategies
      • increment
        • incrementing value, unique to the JVM ( long, short, int )
      • native
        • picks other strategies, depending on the database capabilities ( long, short, int )
      • identity
        • identity column types in DB2, MS SQL Server, Sybase, MySQL, etc ( long, short, int )
      • sequence
        • incrementing sequence in DB2, PostgreSQL, Oracle, etc ( long, short, int )
      • hilo
        • high- and low-value algorithm, unique to database instance ( long, short, int )
      • uuid.hex
        • Hibernate UUID algorithm, unique to a subnet ( String )
      • guid
        • database GUID algorithm for MySQL and MS SQL Server, introduced in Hibernate3 ( String )
      • assigned
        • the application assigns identifier values
    • Hibernate type system
      • Entity types (e.g. User , Category , Item )
        • own database identity (primary key)
        • references are foreign keys
        • own lifecycle independent of other entities
        • shared references are possible
        • usually user-defined classes
      • Value types (e.g. Address, String, Integer )
        • no database identity
        • lifespan of value object is bound to containing entity
        • built-in JDK types and user-defined types
    • Built-in value types
      • integer, long, short, float, double, character, byte, boolean, yes_no, true_false
        • map Java primitives or wrapper classes
      • string
        • maps java.lang.String
      • date, time, timestamp
        • mappings for java.util.Date and subclasses
      • calendar, calendar_date
        • mappings for java.util.Calendar
      • big_decimal
        • maps java.math.BigDecimal
      • locale, timezone, currency, class
        • mappings for miscellaneous JDK classes
      • binary, text
        • mappings for binary (byte array) or text (string) data
      • blob, clob
        • mappings for java.sql.Blob, java.sql.Clob
      • serializable
        • maps a serializable Java object to a binary data type – do not use this!
    • Composition in our object model
      • Classes can have a composition relationship:
      User Address home billing class User { private Long id; private Address homeAddress; private Address billingAddress; } class Address { private String street; private String zipcode; private String city; }
    • Mapping components
      • We sometimes map the composed object to the same table
        • USER table with STREET , ZIPCODE , CITY columns
      <class name=&quot;User&quot; table=&quot; USER &quot;> <id name=&quot;id&quot; column=&quot;USER_ID&quot;> <generator class=&quot;native&quot;/> </id> <component name=&quot;homeAddress&quot; class=&quot;Address&quot;> <property name=&quot;street&quot; column=&quot; HOME_STREET &quot; not-null=&quot;true&quot;/> <property name=&quot;city&quot; column=&quot; HOME_CITY &quot; not-null=&quot;true&quot;/> <property name=&quot;zipcode&quot; column=&quot; HOME_ZIPCODE &quot; not-null=&quot;true&quot;/> </component> ... </class>
    • Bidirectional component mapping
      • We can even make the relationship bidirectional:
        • we can't have shared references to Address objects
        • a null homeAddress will be represented as null values in all columns
      <component name=&quot;homeAddress&quot; class=&quot;Address&quot;> <parent name=&quot;user&quot;/> <property name=&quot;street&quot; column=&quot; HOME_STREET &quot; not-null=&quot;true&quot;/> <property name=&quot;city&quot; column=&quot; HOME_CITY &quot; not-null=&quot;true&quot;/> <property name=&quot;zipcode&quot; column=&quot; HOME_ZIPCODE &quot; not-null=&quot;true&quot;/> </component>
    • Class inheritance hierarchies
      • Three strategies to map an inheritance hierarchy:
        • table per concrete class: no polymorphism
        • table per class hierarchy: denormalization and discriminator
        • table per subclass: using &quot;has a&quot; foreign key relationships
      BillingDetails CreditCard BankAccount
    • Table per concrete class mapping
        • polymorphic associations to BillingDetails are difficult
        • a query against the superclass is several SELECTs
        • changes to the superclass require multiple table changes
        • no special Hibernate mapping, just <class>
      << table >> CREDIT_CARD CREDIT_CARD_ID << PK >> OWNER NUMBER TYPE EXP_DATE << table >> BANK_ACCOUNT BANK_ACCOUNT_ID << PK >> OWNER NUMBER BANK_NAME BANK_SWIFT
    • Table per class hierarchy
        • note the type discriminator column
        • best performance, polymorphic queries and associations
        • subclass columns must be nullable!
        • we use the Hibernate <subclass> mapping
      << table >> BILLING_DETAILS BILLING_DETAILS_ID << PK >> BILLING_TYPE << discriminator >> OWNER NUMBER CREDIT_CARD_TYPE CREDIT_CARD_EXP_DATE BANK_ACCOUNT_NAME BANK_ACCOUNT_SWIFT
    • Mapping a class hierarchy to a single table
        • <subclass> elements can be nested
        • mapping strategy has to be used for all classes in the sub-hierarchy
      <class name=&quot;BillingDetails&quot; table=&quot;BILLING_DETAILS&quot;> <id name=&quot;id&quot; column=&quot;BILLING_DETAILS_ID&quot;> <generator class=&quot;native&quot;/> </id> <discriminator column=&quot;BILLING_TYPE&quot;/> <property name=&quot;name&quot; column=&quot;OWNER&quot;/> ... <subclass name=&quot;CreditCard&quot; discriminator-value=&quot;CC&quot; > <property name=&quot;type&quot; column=&quot;CREDIT_CARD_TYPE&quot;/> ... </subclass> ... </class>
    • Table per subclass
        • normalized model
        • polymorphic associations even to particular subclasses
        • we use the Hibernate <joined-subclass> mapping
      << table >> CREDIT_CARD CREDIT_CARD_ID <<PK>> <<FK>> TYPE EXP_DATE << table >> BANK_ACCOUNT BANK_ACCOUNT_ID <<PK>> <<FK>> BANK_NAME BANK_SWIFT << table >> BILLING_DETAILS BILLING_DETAILS_ID <<PK>> OWNER NUMBER
    • Mapping a joined subclass to normalized tables
        • <joined-subclass> can be nested, but not <subclass>
        • difficult to implement by hand
        • ad hoc reporting might be more complex
      <class name=&quot;BillingDetails&quot; table=&quot;BILLING_DETAILS&quot;> <id name=&quot;id&quot; column=&quot;BILLING_DETAILS_ID&quot;> <generator class=&quot;native&quot;/> </id> <property name=&quot;name&quot; column=&quot;OWNER&quot;/> ... <joined-subclass name=&quot;CreditCard&quot; > <key column=&quot;CREDIT_CARD_ID&quot;/> <property name=&quot;type&quot; column=&quot;CREDIT_CARD_TYPE&quot;/> ... </joined-subclass> ... </class>
    • Class associations
      • A bidirectional one-to-many entity association:
      • Managed associations:
        • a change to one side is immediately reflect on the other side
        • e.g. bid.setItem(item) executes item.getBids().add(bid)
        • used with container-managed relationships (CMR) in EJB/CMP
      • POJOs do not have automatically managed associations!
        • the common Java semantics apply
        • we have to manually set both &quot;ends&quot; of the &quot;link&quot;
        • Hibernate doesn't interfere with POJO semantics!
      Item Bid 0..*
    • The tables of this association mapping << table >> ITEM ITEM_ID <<PK>> NAME PRICE ... << table >> BID BID_ID <<PK>> ITEM_ID <<FK>> AMOUNT ... PRICE NAME ITEM_ID 1 2 3 Bar Foo Baz 2.00 50.00 1.00 ITEM AMOUNT ITEM_ID BID_ID 1 2 3 1 1 2 10.00 20.00 55.00 BID
    • Mapping a unidirectional association
        • The column ITEM_ID is a FK to the PK of the ITEM table.
      class Bid { private Item item; public void setItem(Item i) { this.item = i; } public Item getItem() { return item; } } <class name=&quot;Bid&quot; table=&quot;BID&quot;> ... <many-to-one name=&quot;item&quot; class=&quot;Item&quot; column=&quot;ITEM_ID&quot; not-null=&quot;true&quot;/> </class>
    • Making the association bidirectional
        • The key element refers to the ITEM_ID column in the BID table.
      class Item { private Set bids = new HashSet(); public void getBids() { return bids; } public void addBid(Bid b) { this.bids.add(b) b.setItem(this) // Manage association! } } <class name=&quot;Item&quot; table=&quot;ITEM&quot;> ... <set name=&quot;bids&quot;> <key column=&quot;ITEM_ID&quot;/> <one-to-many class=&quot;Bid&quot;/> </set> </class>
    • The big problem
      • We have referenced the ITEM_ID in two mappings
        • At runtime, we have two in-memory representations of this associtaion, the item property of the Bid and the bids of the Item . Suppose we modify this association:
      Hibernate does not transparently detect the fact that the two changes refer to the same database column, since at this point we have done nothing to indicate that this is a bidirectional association. item.getBids().add(newBid); newBid.setItem(item);
    • Making the association bidirectional
      • We have to declare one end as inverse:
        • changes to the inverse end will be ignored!
        • without inverse=“true” , Hibernate would try to issue two UPDATE statements
      <class name=&quot;Item&quot; table=&quot;ITEM&quot;> ... <set name=&quot;bids&quot; inverse=&quot;true&quot; > <key column=&quot;ITEM_ID&quot;/> <one-to-many class=&quot;Bid&quot;/> </set> </class>
    • Mapping collections vs Java collections Persists an unordered,non-unique many-to-many collection using a surrogate key. java.util.List idbag Persists an indexed, non-unique collection of primitive values N/A primitive-array Persists an indexed, non-unique collection of values or objects N/A array Persists an unordered, non-unique collection of values or objects java.util.List bag Persists an ordered,non-unique collection of values or objects java.util.List list Persists a collection of key/value pairs java.util.Map map Persists an unordered,unique collection of values or objects java.util.Set set Description Java Collection Type Hibernate Collection Type
    • One-to-many association <hibernate-mapping package=“demo”> <class name=“Event” table=“events”> … . <set name=“speakers”> <key column=“event_id”/> <one-to-many class=“Speaker”/> </set> <set name=“attendees”> <key column=“event_id”/> <one-to-many class=“Attendee”/> </set> … . </class> </hibernate-mapping> public class Event { private Set speakers; private set attendees; public void setSpeakers(Set speakers) { this.speakers=speakers;} public set getSpeakers() {return this.speakers;} public void setAttendees(Set attendees) { this.attendees=attendees;} public set getAttendees() {return this.attendees;}
    • One-to-many events events events attendees id bigint(pk) id bigint (pk) event_id bigint (fk) A one-to-many association from events to attendees
    • Many-to-many
      • Suppose Attendees can attend more than one Event. This is a
      • Many-to-many mapping for the set of Attendees:
      • <set name=“attendees” table=“event_attendees”>
      • <key column=“event_id”>
      • <many-to-many column=“attendee_id” class=“Attendee”/>
      • </set>
    • many-to-many events events events event_attendees id bigint(pk) event_id bigint (fk) attendee_id bigint (fk) A many-to-many table schema from events to attendees events events attendees id bigint(pk)
    • Persisting collections of values
      • The below mapping definition for a persistent set of Integers
      • <set name=“ratings” table=“event_ratings”>
      • <key column=“event_id”/>
      • <element column=“rating” type=“integer”
      • </set>
      • The table attribute defines the event_ratings table, which is
      • Used to store the values.
    • Lists
      • Unlike Set, Lists can contain duplicate elements. Since Lists are
      • Indexed, meaning that contained elements are stored at a specific
      • Location in the List, you need to define a <list-index> element:
      • <list name=“speaker”>
      • <list-index column=“speaker_index”/>
      • <key column = “event_id”/>
      • <one-to-many class=“Speaker”/>
      • </list>
    • Maps
      • Maps store entries in key/value pairs, meaning that we retrieve the
      • Value by looking up the associated key.
      • <map name=“speakers”>
      • <map-key column=“speakers_index” type=“string” length=“20”/>
      • <key column=“event_id”/>
      • <one-to-many class=“speaker”/>
      • </map>
      • Inserting elements into the map, use a String for the key
      • Map speakers = new HashMap();
      • speakers.put(“speakers1”, new Speaker());
      • speakers.put(“speakers2”,new Speaker());
      • Event event = new Event();
      • event.setSpeakers(speakers);
    • Bags
      • To store a collection of objects without worrying about ordering
      • Or duplicate elements. This is where Bags come in :
      • <bag name=“speakers”>
      • <key column=“event_id”/>
      • <one-to-many class=“Speaker”/>
      • </bag>
      • For the javabean’s perspective, the collection of Speakers is a List.
      • Import java.util.List;
      • Public class Event
      • {
      • Private List speakers;
      • Public void setSpeakers(List speakers)
      • { this.speakers = speakers;}
      • Public List getSpeakers() { return this.speakers;} }
      • However, using a Bag for Hibernate means you don’t need to explicitly create an index column.
      • Set and Bag both doesn’t require an index column, but remember that a Set can’t contain duplicate elements, whereas Bags can
    • idbags
      • Suppose we have a many-to-many association between Events and Speakers. Speakers can belong to the same Event multiple times, so we can’t use a Set.
      • We also need to ensure fast and efficient access to the many-to-many table event_speakers. We really need to be able to assign a primary key to the event_speakers table. This is where idbags come in:
      • <idbag name=“speakers” table=“event_speakers”
      • lazy=“true” cascade=“all”>
      • <collection-id type=“long” column=“event_speakers_id”>
      • <generator-class=“native”/>
      • </collection-id>
      • <key column=“event_id”/>
      • <many-to-many class=“Speaker” column=“speaker_id”/>
      • </idbag>
    • idbags events events events event_attendees id bigint(pk) event_id bigint speaker_id bigint events events speakers id bigint(pk) event_speaker_id bigint (PK)
    • Lazy collections
      • A lazy collection is populated on demand. It means that the collection of entity objects or values is populated only when the application accesses the collection.
      • Populating the collection happens transparently when the collection is first accessed.
      • Why lazy collections?
      • A collection of objects can possibly contain hundreds or thousands
      • of objects, and the application may not need to access the collection immediately, or at all. Loading hundreds of persistent objects for no reason will certainly impact application performance. It’s better to populate the persistent collection only when it is needed.
    • Lazy collections – Session closed problem
      • To populate a lazy collection, the same Session instance used to retrieve the persistent object from the database must be open when the collection is populated.
      • The following code is incorrectly attempts to load the collection of
      • attendees for an Event after the Session has been closed:
      • Session session =factory.openSession();
      • Event event = session.get(Event.class,eventId);
      • Session.close();
      • Set attendees = event.getAttendees();
    • Lazy collections – correct method
      • Session session =factory.openSession();
      • Event event = session.get(Event.class,eventId);
      • Set attendees = event.getAttendees();
      • Session.close();
      • Persistent collections are lazy by default in Hibernate 3. For non-lazy collections, you must explicitly declare them as lazy=“false” in the mapping definition. For example:
      • <set name=“attendees” lazy=“false”>
      • <key column=“event_id”/>
      • <one-to-many class=“Attendee”/>
      • </set>
    • Lazy collections – multitier problems
      • Any collection, including collections of values and arrays, can be declared not to be “lazy’.
      • The problem with lazy collections in populating them in a multitier application, such as web application,where keeping the Session
      • open can be tricky.
      • Solution : The only requirement is that a Hibernate Session must
      • Be available in the view tier, which is possible when you use a servlet filter or spring to manage your Session instances.
    • Sorted Collections
      • A common requirement when dealing with collection is to sort them
      • According to some criteria. The sorting criteria can be fixed or arbitrary, depending on application requirements.
      • Hibernate supports sorting sets,maps and bags.
      • <set name=“attendees” order-by=“last_name”>
      • <key column=“event_id”/>
      • <one-to-many class=“Attendee”/>
      • </set>
      • few more examples:
      • ordery-by = “last_name, first_name”
      • order_by = “last_name, first_name asc”
      • Use Filter to a collection
      • Set sortedAttendees = session.filter(event.getAttendees(),
      • “ order by this.phoneNumber”);
    • Filters
      • Filters allow you to apply filtering criteria to returned objects at the Session level. You can pass parameters to filters, and they work with classes or collections.
      • To use filters, you first define them in the mapping files, and then enable a given filter by name when using the Session object.
      • <hibernate-mapping>
      • <filter-def name=“nameFilter”>
      • <filter-param name=“nameFilterParam” type=“string”/>
      • </fliter-def>
      • </hibernate-mapping>
    • Filters - 2
      • With the filter defined, we can apply it to persistent classes and colections :
      • <class name = “Event”>
      • <filter name=“nameFilter”
      • condition = “:nameFilterParam=name”/>
      • <set name=“attendees”>
      • <filter name=“nameFilter”
      • condition = “:nameFilterParam = last_name”/>
      • </set>
      • </class>
    • Filters - 3
      • This code applies the filter to the name column in the events table, and to the last_name column in the attendees table.
      • To apply the filters, we must explicitly enable them at the Session level ;
      • Filter f = session.enablefilter(“nameFilter”);
      • f.setParameter(“nameFilterParam”, “Plenary”);
      • List results = session.createQuery(“from Event”).list();
      • This code enables the named filter ant then sets the filter parameter. This results will only contain instances of Event with the name Plenary.
      • We can also enable multiple filters per session.
    • Metadata alternatives
      • Attribute-oriented metadata
        • JSR-175 annotations support, coming soon!
        • XDoclet Hibernate module
      • Hibernate mapping metadata can be manipulated programmatically
        • we can use dom4j or JDOM to generate mapping files in memory
        • we can manipulate the Hibernate Configuration metamodel directly
        • let's demonstrate this my adding a property to a mapped class…
      /** * @hibernate.class * table=&quot;CATEGORY&quot; */ public class Category { ... /** * @hibernate.property */ public String getName() { return name; } ... }
    • Adding a property at runtime // Get the existing mapping for User from Configuration PersistentClass userMapping = cfg .getClassMapping(User.class); // Define a new column for the USER table Column column = new Column(); userMapping.getTable().addColumn(column); // Wrap the column in a Value SimpleValue value = new SimpleValue(); value.setTable( userMapping.getTable() ); value.addColumn(column); // Define a new property of the User class Property prop = new Property(); prop.setValue(value); prop.setName(&quot;motto&quot;); userMapping.addProperty(prop); // Build a new session factory, using the new mapping SessionFactory sf = cfg.buildSessionFactory();
    • Reading metadata at runtime
      • There is also the runtime metamodel , exposed via the SessionFactory :
      Category category = ...; ClassMetadata meta = sessionFactory.getClassMetadata(Category.class); String[] metaPropertyNames = meta.getPropertyNames(); Object[] propertyValues = meta.getPropertyValues(category);