views:

48

answers:

2

Hello

I'm new to JPA and using persistence in Java anyway and I have two questions I can't quite work out: I have generated tags as:

@JoinColumn(name = "UserName", referencedColumnName = "UserName")
@ManyToOne(optional = false)
private User userName;
@JoinColumn(name = "DatasetNo", referencedColumnName = "DatasetNo")
@ManyToOne(optional = false)
private Dataset datasetNo;

But in one of the constructors for the class, no reference is made to columns UserName or DatasetNo whereas all other columns in the class are referenced in the constructor.

Can anyone tell me why this is? Both columns UserName and DatasetNo are 'foreign keys' on the entity Visualisation which corresponds to a database table of the same name. I can't quite work out the ORM.

And when using entity classes, or POJO, is it better to have class variables like:

private User userName;

Where an instance of a class is specified or simply the key of that class instance like:

private String userName;

Thanks

Mr Morgan.

+2  A: 

The way the constructor was written is just a feature of whichever auto-generation tool you used to create your classes from the schema. If you want a constructor that takes them, feel free to add it. Would need to know which one you used and how it was configured to comment on why it worked that way :)

It's normally preferrable to have the actual object relationships mapped. That is the entire point of ORM afterall, no? To have an actual, usable domain of objects that maps to what's in the database, rather than dumb structs that require further manipulation to be made into usable business objects. You'll also need them if you want to be able to write object queries sensibly.

It's much nicer to write:

Select roles from UserRoles roles where role.user.isAdmin = true

than

Select roles from UserRules roles join Users u on roles.userName = u.userName where u.isAdmin = true

Depending on your display technology it can also be helpful for view binding to have real object relationships.

Do note the property names created by your autogeneration tool are also arbitrary. There is no requirement they match the column names.

public User getUserName() is in fact rather silly.
You can certainly change it to public User getUser()

Affe
Thanks for the answers. I'm happy to leave the object references in place, i.e. private Dataset dataset; But I will probably use POJOs rather than the JPA tags even if it means I have to write some of the ORM myself - I've had bad luck with JPA before. It is a small system of some 20 core tables in all so hand writing ORM code using Prepared Statements won't be so onerous a task. Other system tables will be dynamically created with varying numbers of attributes so using JPA for these will not be possible anyway.
Mr Morgan
+1  A: 

First of all, per specification, an entity must have a public or protected no-arg constructor. It may have other constructors but JPA doesn't care of them so feel free to add whatever you want/need as long as you provide a no-arg constructor.

Secondly, when working with an ORM, you need to "forget columns and foreign keys" and think objects and associations, the ORM will take care of foreign keys and joins for you.

So I would actually expect to see something like this:

@JoinColumn(name = "UserName", referencedColumnName = "UserName")
@ManyToOne(optional = false)
private User user;
@JoinColumn(name = "DatasetNo", referencedColumnName = "DatasetNo")
@ManyToOne(optional = false)
private Dataset dataset;

The difference is subtile (erf, there is technically no difference) but fundamental in what it communicates: attributes of your entities are not foreign keys but instances of other entities (hence the think object and associations).

The same applies when writing queries using JPQL. You need to think object and to navigate through associations. For example, to retrieve in JPQL the userName of a User for a given... well, let's call Foo the entity holding User and Dataset here:

select f.user.userName from Foo f where f.id = :id
Pascal Thivent