Persistence API - magic?

N

nroberts

I'm a little confused about how and why the persistence API is even
being used, let alone how it works, in this tutorial I just went
through.

I followed the instructions in this tutorial:
http://programming.manessinger.com/tutorials/an-eclipse-glassfish-java-ee-6-tutorial/

What I'm trying to figure out is how the "entity" classes that eclipse
created with the JPA tools work so I can make my own if I need to.

One tutorial on persistence that I found (
http://www.javaworld.com/javaworld/jw-01-2008/jw-01-jpa1.html?page=3 )
explains how to make them by hand but it uses an orm.xml or
annotations to tell Java what table and what columns to connect an
entity object with. The eclipse stuff doesn't seem to do that at
all. The orm.xml file exists, but it's practically empty containing
nothing but the root element and xml tag. Here's an example entity:

@Entity
public class Zip extends com.manessinger.util.jpa.Entity implements
Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;

private String code;

private String name;

//bi-directional many-to-one association to Country
@ManyToOne
private Country country;
// ... getters and setters...
}

I was thinking that perhaps it was order based, but the order of the
columns in the zip table to do not match. COUNTRY_ID comes between ID
and CODE. The names are close but the case is different and the
"country" column is actually COUNTRY_ID.

The manessinger Entity base doesn't have anything interesting but some
id utility functions:

public abstract class Entity {
public static boolean isId(Integer id)
{
return (id != null && id > 0);
}

public boolean hasId()
{
return isId(getId());
}

public abstract Integer getId();
}

The information doesn't seem to be at the query site either:

Query q = em.createQuery("select co from Country co");
result = (List<Country>)q.getResultList();

What are the rules that Java is using in order to tell what I want
here and do it? As it stands it seems to almost be intuitively
interpreting what I want to do, which I know is impossible. Why does
this code work?
 
A

Arved Sandstrom

I'm a little confused about how and why the persistence API is even
being used, let alone how it works, in this tutorial I just went
through.

I followed the instructions in this tutorial:
http://programming.manessinger.com/tutorials/an-eclipse-glassfish-java-ee-6-tutorial/

I won't discourage you from trying out Java EE 6, but it's a big jump up
from what you're able to do with JBoss 4. I expect you knew that.

Looking at this particular tutorial, my recommendation is, stick with
the Java EE tutorial, and then more focused third-party tutorials. This
Manessinger fellow is simply covering way too much stuff, with not
nearly enough detail for most of it. I wouldn't steer anyone to this
tutorial - my 2 cents worth. YMMV.
What I'm trying to figure out is how the "entity" classes that eclipse
created with the JPA tools work so I can make my own if I need to.

One tutorial on persistence that I found (
http://www.javaworld.com/javaworld/jw-01-2008/jw-01-jpa1.html?page=3 )
explains how to make them by hand but it uses an orm.xml or
annotations to tell Java what table and what columns to connect an
entity object with.

I won't swear to it but that's probably a good JPA tutorial for JBoss 4,
because it's a JPA 1.0 tutorial and I'd be surprised if JBoss 4 supports
JPA 2.0.

You won't need an orm.xml at this point, if ever - stick to
persistence.xml and annotations.
The eclipse stuff doesn't seem to do that at
all. The orm.xml file exists, but it's practically empty containing
nothing but the root element and xml tag.

Basically, as I suggested above, you can ignore the orm.xml. I've almost
never had one myself.
Here's an example entity:

@Entity
public class Zip extends com.manessinger.util.jpa.Entity implements
Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;

private String code;

private String name;

//bi-directional many-to-one association to Country
@ManyToOne
private Country country;
// ... getters and setters...
}

I was thinking that perhaps it was order based, but the order of the
columns in the zip table to do not match. COUNTRY_ID comes between ID
and CODE. The names are close but the case is different and the
"country" column is actually COUNTRY_ID.

Order is not important. Also (and this anticipates a comment below) JPA
uses a fair bit of convention over configuration, so there are set rules
that dictate why the default PK for the referenced table is COUNTRY_ID.
This is in the JPA APIs and specification.

If you want to change from the defaults then there are various
annotations and annotation attributes that let you do that.
The manessinger Entity base doesn't have anything interesting but some
id utility functions:

public abstract class Entity {
public static boolean isId(Integer id)
{
return (id != null && id > 0);
}

public boolean hasId()
{
return isId(getId());
}

public abstract Integer getId();
}

This is a fairly unnecessary base class for entity classes if that's all
it does. I don't even like the premise of that abstract class. Ignore
it, and keep the "id" (whatever the @Id field is called actually)
accessors in the entity classes.

There's nothing wrong with having a entity base class though.
@MappedSuperclass is designed for this purpose better than what Mr
Manessinger devised. At this stage of the game I wouldn't bother with this.
The information doesn't seem to be at the query site either:

Query q = em.createQuery("select co from Country co");
result = (List<Country>)q.getResultList();

What are the rules that Java is using in order to tell what I want
here and do it? As it stands it seems to almost be intuitively
interpreting what I want to do, which I know is impossible. Why does
this code work?

See above - JPA API docs and the specification. And I strongly recommend
the JPA section of the Java EE tutorial.

AHS
 
M

markspace

One tutorial on persistence that I found (
http://www.javaworld.com/javaworld/jw-01-2008/jw-01-jpa1.html?page=3 )
explains how to make them by hand but it uses an orm.xml or
annotations to tell Java what table and what columns to connect an
entity object with. The eclipse stuff doesn't seem to do that at
all. The orm.xml file exists, but it's practically empty containing
nothing but the root element and xml tag.


I'm actually working on learning some JPA/JSF stuff right now too. The
orm.xml stuff confuses me because I haven't seen it before. I'm used to
a persistence.xml file being used. I'm concerned about versions here
and portability, because you seem to be configuring the tool directly,
and not using the JPA config file.

Does anyone know what this config file is about? What version of the
library uses it? It either seems specific to his library, and therefore
non-portable, or it's really old.

I was thinking that perhaps it was order based, but the order of the
columns in the zip table to do not match.


It's based on name, afaik. The entity manager will strip off the "get"
or "set" of your accessors/mutators, or it will use the field name, and
look up a column of the same name. Sometimes case doesn't matter (may
depend on your database, i.e., it could be non-portable to rely on case
insensitivity). There's also ways of mapping from one column to an
object property if the names are different.

COUNTRY_ID comes between ID
and CODE. The names are close but the case is different and the
"country" column is actually COUNTRY_ID.

@Entity
public class MyClass {
@Id
int id;
@Column( name="COUNTRY_ID" )
String country;
...
}
 
L

Lew

nroberts said:
I'm a little confused about how and why the persistence API is even
being used, let alone how it works, in this tutorial I just went
through.

I followed the instructions in this tutorial:
http://programming.manessinger.com/tutorials/an-eclipse-glassfish-java-ee-6-tutorial/

What I'm trying to figure out is how the "entity" classes that eclipse
created with the JPA tools work so I can make my own if I need to.

One tutorial on persistence that I found (
http://www.javaworld.com/javaworld/jw-01-2008/jw-01-jpa1.html?page=3 )
explains how to make them by hand but it uses an orm.xml or
annotations to tell Java what table and what columns to connect an
entity object with. The eclipse stuff doesn't seem to do that at
all. The orm.xml file exists, but it's practically empty containing
nothing but the root element and xml tag. Here's an example entity:

@Entity
public class Zip extends com.manessinger.util.jpa.Entity implements
Serializable {
private static final long serialVersionUID = 1L;

Please, please, please do not use TAB characters to indent code on Usenet!

Use spaces, up to four per indent level.
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;

private String code;

private String name;

//bi-directional many-to-one association to Country
@ManyToOne
private Country country;
// ... getters and setters...
}

I was thinking that perhaps it was order based, but the order of the
columns in the zip table to do not match. COUNTRY_ID comes between ID
and CODE. The names are close but the case is different and the
"country" column is actually COUNTRY_ID.

The manessinger Entity base doesn't have anything interesting but some
id utility functions:

public abstract class Entity {
public static boolean isId(Integer id)
{
return (id != null && id > 0);
}

public boolean hasId()
{
return isId(getId());
}

public abstract Integer getId();
}

The information doesn't seem to be at the query site either:

Query q = em.createQuery("select co from Country co");

This looks like SQL but is most definitely not SQL. It is a request to obtain a collection (an object-oriented concept) of Country objects. It is not a set of table rows.
result = (List<Country>)q.getResultList();

As you see in this simple example, the sensibility of JPA is object-oriented. This differs significantly from the relational algebra at the heart of the data-oriented sensibility of RDBMSes.
What are the rules that Java is using in order to tell what I want
here and do it? As it stands it seems to almost be intuitively
interpreting what I want to do, which I know is impossible. Why does
this code work?

It is like magic, which is both a strength and a source of potential confusion.

By default the JPA mechanism matches based on the class and attribute names.. An entity type like 'Zip' maps to a similarly-named table, "zip". You can set up the persistence.xml to have the system actually create the tablesfor you as it executes the code.

The attributes of a class, such as 'id', map to similarly-named columns in the table by default, e.g., "id".

As Arved pointed out, you can override these defaults with annotations. See the Java EE tutorial for details.
<http://java.sun.com/javaee/6/docs/tutorial/doc/bnbpy.html>

The persistence.xml interacts with the application server's configuration files (such as server.xml and web.xml in Tomcat) to link to a database system.

Relations are mapped to collections of objects. If you do JPA right, you almost never have to refer to an id field (in the SQL sense, an id column)_explicitly. You do have to involve the "natural" keys of your object types in the 'equals()' and 'hashCode()' (and as Josh Bloch and others suggest, the 'toString()') methods. (Auto-generated integer surrogate keys are anathema!)

JPA works best when the entity types are simple.
 
L

Lew

markspace said:
I'm actually working on learning some JPA/JSF stuff right now too. The
orm.xml stuff confuses me because I haven't seen it before. I'm used to
a persistence.xml file being used. I'm concerned about versions here
and portability, because you seem to be configuring the tool directly,
and not using the JPA config file.

Does anyone know what this config file is about? What version of the
library uses it? It either seems specific to his library, and therefore
non-portable, or it's really old.

I'm pretty sure it's a Hibernatism, supplanted by persistence.xml for all practical purposes.

"Country" in JPA is NOT A COLUMN! It's a type.

It will contain a column for the id, or perhaps more than one. But it's a representation of the "country" table, not just one column.

Get this, because it's the biggest single mistake people make with JPA. 'Country' is an entity! It is an entity. It is not a column. It is an entity.

A whole entity, with attributes. There are no columns in objects. Classesdon't have columns, they have attributes or fields. Tables don't have fields, they have columns. JPA is about objects, not tables. Country is a type, that is, an entity in an object-oriented sense.

I'm being deliberately repetitive here because it is the key. COUNTRY IS NOT A COLUMN!
@Entity
public class MyClass {
@Id
int id;
@Column( name="COUNTRY_ID" )
String country;

NO! NO! NO! NO!

'Country country;' with an '@ManyToOne'. NOT A COLUMN! It is an OBJECT RELATIONSHIP, NOT A COLUMN!

Bad JPA there, bad!

You specify the column inside the '@ManyToOne' annotation, not as a field in the 'MyClass' (terrible name for an entity!).
 
M

markspace

I'm pretty sure it's a Hibernatism, supplanted by persistence.xml for
all practical purposes.


Thanks for pointing that out!

'Country country;' with an '@ManyToOne'. NOT A COLUMN! It is an
OBJECT RELATIONSHIP, NOT A COLUMN!


Oops, I didn't read his example carefully, and I missed that.

So what's going on there is that Country is an entity too:

@Entity
public class Country {
@Id
int id;
String name; // ? other properties...
....
}

And JPA will automatically put a foreign key in the table "Zip" that
relates to the primary key in the table "Country" (I'm using class names
here because you didn't specify differently, e.g. using
@Table(name="A_TABLE_NAME")) and then JPA will do the join for you.

However, watch out for lazy loading and detachment.

You specify the column inside the '@ManyToOne' annotation, not as a
field in the 'MyClass' (terrible name for an entity!).


Yeah the "MyClass" was just to make it abundantly clear that my example
wasn't related to the code posted by N. Roberts.
 
A

Arved Sandstrom

I'm actually working on learning some JPA/JSF stuff right now too. The
orm.xml stuff confuses me because I haven't seen it before. I'm used to
a persistence.xml file being used. I'm concerned about versions here
and portability, because you seem to be configuring the tool directly,
and not using the JPA config file.

Does anyone know what this config file is about? What version of the
library uses it? It either seems specific to his library, and therefore
non-portable, or it's really old.

It's portable and it's JPA. orm.xml is the object-relational mapping
file for JPA; it's been around from the gitgo and is still very much in
play. You can define your mappings using annotations in entity classes,
or using orm.xml, or both.

As I suggested to the OP earlier, at the moment he can leave his
vestigial Eclipse-generated orm.xml alone, and stick to annotations
only. I'm not discouraging the use of orm.xml at all, but at the
learning stage it can be ignored.
It's based on name, afaik. The entity manager will strip off the "get"
or "set" of your accessors/mutators, or it will use the field name, and
look up a column of the same name. Sometimes case doesn't matter (may
depend on your database, i.e., it could be non-portable to rely on case
insensitivity). There's also ways of mapping from one column to an
object property if the names are different.
[ SNIP ]

It's all based on names, we've got nothing else in play. :)

As I mentioned to the OP previously, this is all defined in the
specifications _and_ in the Javadocs. For example, if @ManyToOne is
under consideration, and @JoinColumn is defaulted, the name of the
referenced table is inferred from the type(name) of object being
referenced. And all other defaults of @JoinColumn kick in.

AHS
 
N

nroberts

I won't discourage you from trying out Java EE 6, but it's a big jump up
from what you're able to do with JBoss 4. I expect you knew that.

Looking at this particular tutorial, my recommendation is, stick with
the Java EE tutorial,

I have not found the tutorial very helpful. It's not very tutorial
like. It just has a bunch of words without many examples and never
seems to get to the meat of things. This particular question does not
appear to be answered there for example. Perhaps it is, somewhere in
all that, but I couldn't find it.

The other tutorials actually show me how to get things done. Most of
it is quite straight forward. Where they glaze things over and I
can't figure it out on my own, I look for other resources and when I
can't find my answer I ask.
 
N

nroberts

It's based on name, afaik.  The entity manager will strip off the "get"
or "set" of your accessors/mutators, or it will use the field name, and
look up a column of the same name.   Sometimes case doesn't matter (may
depend on your database, i.e., it could be non-portable to rely on case
insensitivity).  There's also ways of mapping from one column to an
object property if the names are different.

It must be the field names because I just tried to change one but left
the getter/setter alone. It exploded with a pile of exception vomit.

The country bit also blows up when you change the variable name.
Eclipse error specifically said, "join column kalifornia_id can not be
found." The auto-name recognition thing must append _id to your
variable when you do a join.

I don't think I like the idea of relying on this behavior. Will
probably never use it now that I have some understanding of what it's
doing. Explicit annotations seem much more appropriate and
documenting, even if they're not strictly necessary in many cases.
 
M

markspace

It must be the field names because I just tried to change one but left
the getter/setter alone. It exploded with a pile of exception vomit.


Actually, when I said "or," I meant that literally. Field names:

@Entity
public class Employee {
@Id
int id;
...

@Entity
@Access( AccessType.FIELD )
public class Employee { ...


Properties:


@Entity
public class Employee {
int id;

@Id
public int getId();
public void setId( int id );
....
}

@Entity
@Acces( AccessType.FIELD )
public class Employee {
@Id
int id;

@Access( AccessType.PROPERTY )
@Column( name="PHONE" )
protected String getPhoneForDb() {...}
protected void setPhoneForDb( String phone ) {...}
....
}

The last one is actually mixed and uses both fields and
accessors/mutators (properties).


The country bit also blows up when you change the variable name.
Eclipse error specifically said, "join column kalifornia_id can not be
found." The auto-name recognition thing must append _id to your
variable when you do a join.

My implementation extends the DTO classes you define and adds methods
and such to them. It might be referring to a field or property it added
to your base class.
I don't think I like the idea of relying on this behavior.

That's why there's overrides in the form of @Column(name=) and @Table(name=)
 
L

Lew

"Exception vomit" is vague and hard for us to diagnose. You could have accessors that refer to the old field names, but that would be "compiler vomit", not "exception vomit", assuming I understand your vague and unconventional term correctly. You might have mixed annotations for fields with annotations for accessors, which doesn't work in the JPA implementations I've used. You might have mismatched attribute names and column names. "Exceptionvomit" just doesn't tell us anything useful. I guess that makes the post "Usenet vomit".
Actually, when I said "or," I meant that literally. Field names:

@Entity
public class Employee {
@Id
int id;
...

@Entity
@Access( AccessType.FIELD )
public class Employee { ...


Properties:


@Entity
public class Employee {
int id;

@Id
public int getId();
public void setId( int id );
...
}

@Entity
@Acces( AccessType.FIELD )
public class Employee {
@Id
int id;

@Access( AccessType.PROPERTY )
@Column( name="PHONE" )
protected String getPhoneForDb() {...}
protected void setPhoneForDb( String phone ) {...}
...
}

The last one is actually mixed and uses both fields and
accessors/mutators (properties).

Does that work for you? I seem to remember getting error messages when I tried to mix field and accessor JPA annotations in the same class.

Even if allowed, it's not a good practice.

I have settled on accessor annotation. From a public standpoint, the accessors define the attributes.

If your column names don't match the automagical defaults, you need to specify them in your annotations.

Read the JPA documentation for the details on the naming conventions.
My implementation extends the DTO classes you define and adds methods
and such to them. It might be referring to a field or property it added
to your base class.

That's why there's overrides in the form of @Column(name=) and @Table(name=)

+1

But OP, don't whine that the documentation is too hard. Understand the documentation. It tells you what you need to know, including what the defaultmappings are and how to override them.

You can't complain that you don't know how to do something and that you don't feel like reading the docs. You must read the docs and learn how to do what you want. So the docs are hard - that's why we make the big bucks. You should have started in the days of mainframes - now *those* docs were hard to read. You have it easy - so Shut the Front Up and study. You get nosympathy for "The docs are too difficult! Waaaah!"
 
M

markspace

Does that work for you? I seem to remember getting error messages
when I tried to mix field and accessor JPA annotations in the same
class.


Hmm, I haven't actually tried it. That's copied from a book. I was
going link to this anyway for the op:

Pro JPA 2, by Mike Keith and Merrick Schincariol, Apress

Even if allowed, it's not a good practice.


Yes, the example called it out as being "unusual" but they wanted to
give an example how it would be done, if needed.
 
L

Lew

markspace said:
Hmm, I haven't actually tried it. That's copied from a book. I was
going link to this anyway for the op:

Pro JPA 2, by Mike Keith and Merrick Schincariol, Apress



Yes, the example called it out as being "unusual" but they wanted to
give an example how it would be done, if needed.

The answer to "How would I mix field and accessor JPA annotations?" is the same as Frank Zappa's answer to "How would I break into the music business?" - "Don't."
 
A

Arved Sandstrom

I have not found the tutorial very helpful. It's not very tutorial
like. It just has a bunch of words without many examples and never
seems to get to the meat of things. This particular question does not
appear to be answered there for example. Perhaps it is, somewhere in
all that, but I couldn't find it.

The other tutorials actually show me how to get things done. Most of
it is quite straight forward. Where they glaze things over and I
can't figure it out on my own, I look for other resources and when I
can't find my answer I ask.

There's a tutorial examples bundles that goes along with the tutorial
itself. The very first section has instructions for obtaining the
example code, and setting up environments.

AHS
 
R

Roedy Green

I'm a little confused about how and why the persistence API is even
being used, let alone how it works, in this tutorial I just went
through.

I too have written a blurb on how to use it. See
http://mindprod.com/jgloss/preferences.html

You might find it more accessible.
--
Roedy Green Canadian Mind Products
http://mindprod.com
The modern conservative is engaged in one of man's oldest exercises in moral philosophy; that is,
the search for a superior moral justification for selfishness.
~ John Kenneth Galbraith (born: 1908-10-15 died: 2006-04-29 at age: 97)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top