OpenJPA Reverse Mapping Tool - how to make foreign key primitive? - java

Currently the OpenJPA reverse mapping tool generates the foreign key for entities as object types. Is there a way to make them primitive types?

Whenever you persist a new entity, it inserts '0' in place of an uninitialized primitive type (which is in line with Java initialization defaults for primitives). It would have to be the same with foreign keys, which means OpenJPA would have to generate invalid foreign keys (with "0" id, which is perfectly valid id from DB's point of view).
So, there's only the option:
-nullableAsObject/-no <true/t | false/f>:
By default, all non-foreign key columns are mapped to primitives
but, as noted, it's valid for non-FKs only.

Related

JOOQ: How to resolve foreign keys as objects?

Say I have a table that references another table, in this case "TestScenarios" references "TestSchemas". So each TestScenario HAS-A TestSchema.
I autogenerated DAOs, however, when fetching TestScenario instance via the DAO the TestSchema field is an integer, not a TestSchema-object. How can I get JOOQ to resolve foreign keys directly as objects up to a certain depth?
CREATE TABLE "TestScenarios"
(
id integer DEFAULT nextval('"TestScenarios_id_seq"'::regclass) NOT NULL,
name varchar,
version bigint,
"testSchema" integer,
);
ALTER TABLE "TestScenarios"
ADD CONSTRAINT "TestScenarios_pkey"
PRIMARY KEY (id);
ALTER TABLE "TestScenarios"
ADD CONSTRAINT "testSchemaFk" FOREIGN KEY ("testSchema")
REFERENCES "TestSchemas" (id)
ON UPDATE NO ACTION
ON DELETE NO ACTION;
COMMIT;
DAOs don't have such a feature, but with jOOQ's DSL API, you could use implicit joins to quickly fetch also parent tables for any given child table, e.g.
ctx.select(TestScenarios.asterisk(), TestScenarios.TestSchemas().asterisk())
.from(TestScenarios)
.fetch();
There are other approaches, but there's never going to be anything automatic about "object graph persistence" in the way JPA would offer it, for example. The jOOQ philosophy is to always express every query explicitly - maybe profit from some mapping sugar, but to never implicitly and automatically fetch entire object graphs.

jOOQ - update record based on unique key (not primary key)

I am using jOOQ to generate POJOs for my database tables. This works great.
I have a table with a primary key (identifier) and a unique key (name). When updating the record, jOOQ uses the primary key.
I would like to update the record by using the unique key instead of the primary key.
https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java
#Override
public final int update() {
return update(fields.fields.fields);
}
#Override
public int update(Field<?>... storeFields) throws DataAccessException, DataChangedException {
return storeUpdate(storeFields, getPrimaryKey().getFieldsArray());
}
In essence, I want to call storeUpdate with another key (second parameter). I tried extending the generated record, but storeUpdate is private.
Is there another way to update a record? I could first select the identifier before update(), but it introduces an extra query, which I would like to avoid.
From the comments, I understand that you want to:
Use the generated records as "ActiveRecords" holding data that is going to be stored / updated into a table
Use arbitrary "key" information as selective criteria for your update statement
There are two ways you can do this with jOOQ:
1. Override the primary key information in the code generator
You can specify a regular expression matching unique key names in your database, which should override primary keys in generated code:
<!-- All (UNIQUE) key names that should be used instead of primary keys on
generated UpdatableRecords, to be used with
- UpdatableRecord.store()
- UpdatableRecord.update()
- UpdatableRecord.delete()
- UpdatableRecord.refresh()
If several keys match, a warning is emitted and the first one encountered
will be used.
This flag will also replace synthetic primary keys, if it matches. -->
<overridePrimaryKeys>MY_UNIQUE_KEY_NAME</overridePrimaryKeys>
Note that this solution will affect all the calls to store(), update(), etc. From your comments, this might not be the desired behaviour... For more information, see the jOOQ manual
2. Use a regular UPDATE statement
You can pass the whole UpdatableRecord to an UPDATE statement and specify the selection criteria explicitly, such as:
MyTableRecord record = ...;
DSL.using(configuration)
.update(MY_TABLE)
.set(record)
.where(MY_TABLE.NAME.eq(record.getName())
.execute();

Hibernate assigned generator

The generator element in the hibernate mapping file is supposed to be used to determine how the primary key is generated. Why is the default value assigned bad for detached and transient objects?
If you want the application to assign identifiers, as opposed to having Hibernate generate them, you can use the assigned generator. This special generator uses the identifier value already assigned to the object's identifier property. The generator is used when the primary key is a natural key instead of a surrogate key. This is the default behavior if you do not specify a element.
The assigned generator makes Hibernate use unsaved-value="undefined". This forces Hibernate to go to the database to determine if an instance is transient or detached, unless there is a version or timestamp property, or you define Interceptor.isUnsaved().

JPA 2 (EclipseLink) Trying to use UUID as primary key EntityManager.find() always throws exception (Database is PostgreSQL)

I'm trying to use a UUID for a primary key using JPA 2 (EclipseLink). I'm using PostgreSQL as the database. I have my entity declared as follows: I have an Employee table with its PK set as a UUID. I have a JPA Entity mapping to the employee table, which looks like this:
#Entity
public class Employee {
#Id
private String id;
...
...
}
When I call EntityManager.find(Employee.class, id)
I get an exception from postgres:
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
I have also tried changing the id in the Employee class to java.util.UUID, but then I get the following (very similar error):
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
I'm really not sure how to go about fixing this... anyone have any ideas?
Thanks!
I'm trying to use a UUID for a primary key using JPA 2 (EclipseLink)
Unfortunately, standard JPA doesn't include UUID as a strategy for generated identifiers.
I have also tried changing the id in the Employee class to java.util.UUID (...)
This is not a valid type for an Id (which has been treated as Serializable in your case). The JPA 2.0 specification states:
2.4 Primary Keys and Entity Identity
...
A simple primary key or a field or property of a composite primary key
should be one of the following types:
any Java primitive type; any primitive
wrapper type; java.lang.String;
java.util.Date; java.sql.Date;
java.math.BigDecimal;
java.math.BigInteger. If the
primary key is a composite primary key
derived from the primary key of
another entity, the primary key may
contain an attribute whose type is
that of the primary key of the
referenced entity as described in
Section 2.4.1. Entities whose primary
keys use types other than these will
not be portable. If generated primary
keys are used, only integral types
will be portable. If java.util.Date
is used as a primary key field or
property, the temporal type should be
specified as DATE.
In other words, if there is a solution, it will be provider specific.
I'm really not sure how to go about fixing this... anyone have any ideas?
You need to configure EL for custom sequencing and to provide a custom sequence generator. See EclipseLink/Examples/JPA/CustomSequencing for a full example (using a UUID generator).
The error seems to indicate that your are binding the id as a String, but the database does not allow this. If you access that type directly from JDBC what type is returned? You may need to use this type in your class and map it using a Converter.
See,
http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#Using_EclipseLink_JPA_Converters
EclipseLink also allows setting the JDBC type on the DatabaseField, which may help with binding the type.

Hibernate mapping a composite key with null values

With Hibernate, can you create a composite ID where one of the columns you are mapping to the ID can have null values?
This is to deal with a legacy table that has a unique key which can have null values but no primary key.
I realise that I could just add a new primary key column to the table, but I'm wondering if there's any way to avoid doing this.
No. Primary keys can not be null.
You wont get error but Hibernate wont be able to map those rows with NULL value for composite column to your Entity. That means you get entity with NULL values in result.
Unfortunatly, no. I either had to use a workaround:
I used composit Id for a view(! not table) where rows can be identified by 2 cols exactly (A, B). Although one of the cols (B) can have null values as well as positive integers.
So my workaround is that i created a new col in the view: "BKey" and my view is written as if B is null then value of BKey is -1 else BKey = B. (Only positive integers occour in B and null). I also changed my composit id implementation to use BKey instead of B.
Hope it helps for somebody..
This is not advisable. Could you use a view and map that instead? You could use COALESCE to supply a default if you are stuck with legacy data. We had lots of trouble with composite keys and I imagine null values will cause even more issues.
For composite keys (assumed that database allows nulls in PKs) you can have maximum number_of_cols^2 - 1 entries containing nulls, (for example for composite key of 2 columns you can have 3 rows having in their primary key null, the fourth is the PK without nulls).
Why would you want to do that? Your composite ID should map the primary key of your table, and it doesn't sound wise to put null values in a key, does it?
EDIT: Hibernate does not allow to do so; you might put the property outside the key and tweak the DAO a little to take the field into account wherever necessary

Categories

Resources