JPA2: Using TemporalType=TIMESTAMP as part in a composite primary key - jpa-2.0

In the JavaEE 6 tutorial (http://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html#bnbqf) the following is stated regarding how to map primary keys:
The primary key, or the property or field of a composite primary key, must be one of the following Java language types:
--cut--
java.util.Date (the temporal type should be DATE)
--cut--
What does it mean when it is written "should be DATE"? What are the implications of using TemporalType=TIMESTAMP?
I have a composite primary key which has two fields, a long and a java.util.Date.
In the entity I have the following mapping (not listing the ID-class):
#Id
#Temporal(TemporalType.TIMESTAMP)
private Date startDate;
#Id
private long id;
The above works fine in the unit tests, but I am concerned about the wording above regarding which temporal type to use.
Comments and insights are appreciated!

Related

How to setup Doctrine entity associations when table uses a generic foreign key pattern?

We inherited a 3rd party database schema where several tables use a database
design pattern in which tables do not define foreign keys directly, but in
a way where some tables do so by a combination of two columns:
a column specifying name of table:
either directly (ENUM type)
or by means of another table (type_id referencing table types, which then contains table name in a varchar column)
a column specifying PK value from said table (e.g. type_value)
This results in a scenario where one row references one table while another
row may reference a completely different table.
We can use query builder and define JOIN and WHERE clauses manually for each
scenario, but it'd be more practical to have one property for each foreign
table and use WHERE clause to filter target table results only, e.g.:
class Foo {
private $id; // PK for Foo
private $type; // string (enum), e.g. 'bar' or 'baz'
private $type_id; // contains PK of Bar or Baz, respectivelly
private $bar; // references entity Bar
private $baz; // references entity Baz
}
The closest thing to what we need which I managed to find is to use Criteria API
to update the WHERE clause dynamically in getter methods (as seen here).
However I'm completely lost in terms of how to setup Doctrine annotations in
this case. Does Doctrine support a DB schema such as this one, or do we have to
fall back to building each query manually via query builder or DQL?

Determine if target entity is a foreign key in Doctrine filter

Doctrine passes a $targetEntity and $targetTableAlias to the filter constraint like so:
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{ ...
It appears that all entities pass through the filter when a query is being built. Is there any way to determine if $targetEntity is a foreign key or not? I'd like to write a filter that works on the "primary" entity (what Doctrine calls the "base" table) but not its foreign keys.
Your question is not very clear and I am not sure if this will answer your question, but in the Doctrine 2 documentation chapter 30. Filters you can read the following:
In the case of joined or single table inheritance, you always get passed the ClassMetadata of the inheritance root. This is necessary to avoid edge cases that would break the SQL when applying the filters.
So I would say the $targetEntity is always the root entity (so never a foreign key).
If this doesn't answer your question I would like to ask you to be a bit more specific on what exactly you want to do or what you want to find out.

Cannot make #ManyToOne relationship nullable

I have a many-to-one relationship that I want to be nullable:
#ManyToOne(optional = true)
#JoinColumn(name = "customer_id", nullable = true)
private Customer customer;
Unfortunately, JPA keeps setting the column in my database as NOT NULL. Can anyone explain this? Is there a way to make it work? Note that I use JBoss 7, JPA 2.0 with Hibernate as persistence provider and a PostgreSQL 9.1 database.
EDIT:
I found the cause of my problem. Apparently it is due to the way I defined the primary key in the referenced entity Customer:
#Entity
#Table
public class Customer {
#Id
#GeneratedValue
#Column(columnDefinition="serial")
private int id;
}
It seems that using #Column(columnDefinition="serial") for the primary key automatically sets the foreign keys referencing it to NOT NULL in the database. Is that really the expected behavior when specifying the column type as serial? Is there a workaround for enabling nullable foreign keys in this case?
Thank you in advance.
I found the solution to my problem. The way the primary key is defined in entity Customer is fine, the problem resides in the foreign key declaration. It should be declared like this:
#ManyToOne
#JoinColumn(columnDefinition="integer", name="customer_id")
private Customer customer;
Indeed, if the attribute columnDefinition="integer" is omitted the foreign key will by default be set as the source column: a not-null serial with its own sequence. That is of course not what we want as we just want the to reference the auto-incremented ID, not to create a new one.
Besides, it seems that the attribute name=customer_id is also required as I observed when performing some testing. Otherwise the foreign key column will still be set as the source column. This is a strange behavior in my opinion. Comments or additional information to clarify this are welcome!
Finally, the advantage of this solution is that the ID is generated by the database (not by JPA) and thus we do not have to worry about it when inserting data manually or through scripts which often happens in data migration or maintenance.
I came across this problem but I was able to solve it this way:
#ManyToOne
#JoinColumn(nullable = true)
private Customer customer;
Maybe the problem emerged from declaring #ManyToOne(optional = true)
That is very weird.
In JPA nullable parameter is true by default. I use this kind of configuration all the time and it works fine. If you try to save entity it should be successful.
Did you try to delete table that is created for this relationship? Maybe you have legacy table with that column?
Or maybe you should try to find solution on other chunks of code, because this is proper configuration.
Note: I have tried this configuration on PostgreSQL with JPA2 and Hibernate.
EDIT
In that case maybe you can try a little bit different definition of primary key.
For example you can use definition like this:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column()
private Long id;
and postgresql will generate
id bigint NOT NULL
-- with constraint
CONSTRAINT some_table_pkey PRIMARY KEY (id)
If this is good enough you can try this solution.
within transaction but before the save operation, explicitly set the foreign key column value as null. By this hibernate ,never perform select queries for this foreign key related table and don't throw the exception "save the transient instance before flushing". if you want to set "null value " conditionally, then perform 1. fetch & set the value using repo call get/ find 2. then check the fetched value for the condition and set it to null accordingly .pasted the code below which is tested and found working
// Transaction Start
Optional<Customer> customerObject = customerRepository.findByCustomerId(customer.getCustomerId())
if(customerObject.isPresent())yourEnclosingEntityObject.setCustomer(customerObject)}
else {yourEnclosingEntityObject.setCustomer(null)}
yourEnclosingEntityObjectRepository.save(yourEnclosingEntityObject)
// Transaction End

The differences between GeneratedValue strategies

In the Doctrine docs they mention that there exists a few different strategies for the #GeneratedValue annotation:
AUTO
SEQUENCE
TABLE
IDENTITY
UUID
CUSTOM
NONE
Would someone please explain the differences between all thees strategies?
Check the latest doctrine documentation
Here is a summary :
the list of possible generation strategies:
AUTO (default): Tells Doctrine to pick the strategy that is preferred by the used database platform. The preferred strategies are IDENTITY for MySQL, SQLite and MsSQL and SEQUENCE for Oracle and PostgreSQL. This strategy provides full portability.
SEQUENCE: Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full portability. Sequences are supported by Oracle and PostgreSql and SQL Anywhere.
IDENTITY: Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row. This strategy does currently not provide full portability and is supported by the following platforms:
MySQL/SQLite/SQL Anywhere => AUTO_INCREMENT
MSSQL => IDENTITY
PostgreSQL => SERIAL
TABLE: Tells Doctrine to use a separate table for ID generation. This strategy provides full portability. This strategy is not yet implemented!
NONE: Tells Doctrine that the identifiers are assigned, and thus generated, by your code. The assignment must take place before a new entity is passed to EntityManager#persist. NONE is the same as leaving off the #GeneratedValue entirely.
SINCE VERSION 2.3 :
UUID: Tells Doctrine to use the built-in Universally Unique Identifier generator. This strategy provides full portability.
Ofcourse the accepted answer is correct, but it needs a minor update as follows:
According to Annotation section of the documentation:
This annotation is optional and only has meaning when used in conjunction with #Id.
If this annotation is not specified with #Id the NONE strategy is used as default.
The strategy attribute is optional.
According to Basic Mapping section of the documentation:
SEQUENCE: Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full portability. Sequences are supported by Oracle, PostgreSql and SQL Anywhere.
IDENTITY: Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row. This strategy does currently not provide full portability and is supported by the following platforms:
MySQL/SQLite/SQL Anywhere (AUTO_INCREMENT)
MSSQL (IDENTITY)
PostgreSQL (SERIAL).
Downvote
Regarding the downvote given by someone, it should be noted that SQL Anywhere has been added and the accepted answer needs a minor update.
From the perspective of a programmer, they all achieve the same result: that is to provide a UNIQUE value for the primary key field. Strictly speaking, there are two further conditions which are also met, namely: the key must also be mandatory and not null.
The only differences lie in the internal implementations which provide the primary key value. In addition, there are performance and database-compatibility factors which also need to be considered. Different databases support different strategies.
The easiest one to understand is SEQUENCE and this is generally also the one which yields the best performance advantage. Here, the database maintains an internal sequence whose nextval is accessed by an additional SQL call as illustrated below:
SELECT nextval ('hibernate_sequence')
The next value is allocated during insertion of each new row. Despite the additional SQL call, there is negligible performance impact. With SEQUENCE, it is possible to specify the initial value (default is 1) and also the allocation size (default=50) using the #SequenceGenerator annotation:
#SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
The IDENTITY strategy relies on the database to generate the primary key by maintaining an additional column in the table whose next value is automatically generated whenever a new row is inserted. A separate identity generator is required for each type hierarchy.
The TABLE strategy relies on a separate table to store and update the sequence with each new row insertion. It uses pessimistic locks to maintain the sequence and as a result is the slowest strategy of all these options. It may be worth noting that an #TableGenerator annotation can be used to specify generator name, table name and schema for this strategy:
#TableGenerator(name="book_generator", table="id_generator", schema="bookstore")
With the UUID option, the persistence provider (eg Hibernate) generates a universally unique ID of the form: '8dd5f315-9788-4d00-87bb-10eed9eff566'. To select this option, simply apply the #GeneratedValue annotation above a field declaration whose data type is UUID; eg:
#Entity
public class UUIDDemo {
#Id
#GeneratedValue
private UUID uuid;
// ...
}
Finally, the AUTO strategy is the default and with this option, the persistence provider selects the optimal strategy for the database being used.

JPA2: Can we use multiple #ElementCollection in an Entity?

Here is the stripped down version of my code:
#Entity
public class Item implements Serializable{
#Id
#GeneratedValue
private long id;
#ElementCollection(fetch=FetchType.EAGER ,targetClass=Cost.class)
#CollectionTable(name="ItemCost", joinColumns = {#JoinColumn(name="itemId")})
private Set<Cost> costs= new HashSet<Cost>();
#ElementCollection(fetch=FetchType.EAGER ,targetClass=ItemLocation.class)
#CollectionTable(name="ItemLocation", joinColumns = {#JoinColumn(name="itemId")})
private Set<ItemLocation> itemLocations;
}
Is the above code allowed? I have two embeddable classes Cost and ItemLocation that I am using with #ElementCollection.
Issue:
When I try to run a named query
#NamedQuery(name = "Item.findAll", query = "SELECT i FROM Item i")
I have strange behavior. The records in the second elementcollection (ItemLccation table) are getting doubled (inserted into the table).
What it comes to JPA 2.0, your code is allowed. It is perfectly legal to have more than one collections that are annotated with ElementCollection. Also, it most likely does not have anything to do with problem you have. By the way, to find out is that really your problem, had you tried your code without costs collection?
In which point exactly duplicates in this collection occur first time? If ItemLocation does not define equals&hashcode, duplicates can easily come as result of adding items by yourself.
Possibly you are facing this problem: Primary keys in CollectionTable and chancing type to list and adding #OrderColumn will help.