I'm using JDO (with Datanucleus implementation) for a new project for the first time, and I'm having troubles defining 1-N unidirectional owned relation using JDO annotations. What I need is to have a collection of Subitems in an Item, such that a Subitem doesn't have a reference to the owner:
#PersistenceCapable(detachable = "true")
public class Item {
...
#Persistent(defaultFetchGroup = "true")
Collection<Subitem> subitems;
...
}
It's all well and good, but how can I define which existing RDBMS column the relation maps to? AFAIK an owned 1-N is realized in a DB by creating a non-nullable table column in a child table but I don't have (and don't want) a parent reference class field in a Subitem which I can then decorate with #Column(name="...") annotation.
And how to properly use #ForeignKey annotation in JDO3? The annotation accepts the name of the FK constraint but not the corresponding FK table and column specification. By definition a FK is a ref. constraint between two tables based on a common key, but I can't seem to specify the other table and a common key(#ForeginKey at Datanucleus JDO docs ).
Edit:
#Element(column="...") annotation should be used instead:
#PersistenceCapable(detachable = "true")
public class Item {
...
#Persistent(defaultFetchGroup = "true")
#Element(column="itemId")
Collection<Subitem> subitems;
...
}
As it's clearly stated in the documentation links in the answer.
JDO (or JPA too for that matter) doesn't have "owned" relations, just relations (it is a term I've only ever heard of in relation to GAE's datastore, and you're not using that).
DataNucleus docs defines all such relations adequately IMHO so just navigate the menu from where you got to, for example
http://www.datanucleus.org/products/accessplatform_3_1/jdo/orm/one_to_many_collection.html#fk_uni
http://www.datanucleus.org/products/accessplatform_3_1/jdo/orm/constraints.html#fk
Related
I'm currently using Hibernate & Envers version 5.2.9.Final. I want to use #ElementCollection with a custom table name for both the collection and the audit table.
What I know so far is that modifying default table names has a variety of annotations to work with: For the entity itself there are the annotations #Table and #SecondaryTable as well as the corresponding envers annotations #AuditTable and #SecondaryAuditTable. For changing the table name of an element collection there is the #CollectionTable annotaion. I have not been able to find a corresponding envers annotation so far. So my question is:
How can I change the name for a hibernate #ElementCollection envers audit table?
Additional info
In the hibernate envers ticket which tracks the adding of auditing support for element collections, the same question was asked back in 2013 but not answered.
A code snippet to make my setup clear:
#Entity
#Table(name = "\"user\"")
#SecondaryTable(name = "\"user_secondary\"")
#Audited
#AuditTable("\"user_audit\"")
#SecondaryAuditTable(secondaryTableName = "user_secondary",
secondaryAuditTableName = "\"user_secondary_audit\"")
public class User {
// ... stuff like id and other fields ...
#ElementCollection
#CollectionTable(name = "\"user_references\"")
private Map<String, Long> references = new HashMap<>();
// TODO FIXME how to get a custom name for the audit table?
// ... more stuff like getters and setters
}
Hibernate generates all tables as intended, yet the collecction audit table is named 'user_references_AUD' while I would like to get the name 'user_references_audit' like for the other tables.
I'm also aware of the global settings affecting the audit table prefix or suffix, but that is only a last resort for my use case.
Update
As suggested I added a feature request to Hibernate JIRA.
That is because Envers has no complement for #CollectionTable.
You are welcomed to add a JIRA requesting that we add a complementing annotation and I can look at what is needed to add the functionality. Just at a glance, it shouldn't require too much as it merely needs to feed into the generated Envers entity table name for the collection middle entity.
I'm developing a code generator that have to generate JPA entities from database meta-model files. These model are from home-brewed modeling system which are being used to generate models other than JPA entities.
In these models some fields are mapping back to same database column. But it seems like JPA does not like that very much. When I try to run generated code I get
Exception [EclipseLink-48] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [FACT_INVENT_TRANS_HIST_DM.TRANSACTION_ID]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[TransactionIdKey-->FACT_INVENT_TRANS_HIST_DM.TRANSACTION_ID]
Descriptor: RelationalDescriptor(InventTransHistFactDM --> [DatabaseTable(FACT_INVENT_TRANS_HIST_DM)])
As I can't change the models only option left is to make one of those fields read-only. And the JPA entities being generated are only used to read data from database it will not used for writing data. Is there a way to mark some fields as read only or tell EclipseLink that these entities are read only so it does not have to worry about the multiple writable mapping.
I tried using EclipseLink's #ReadOnly annotation in all entities but it did not help this issue.
There is no #ReadOnly in JPA.
There are however attributes "insertable"/"updatable" that you can set against a field via #Column to effectively do the same.
The question may be almost 6 years old, but it's still being found today, so I'd like to address another option:
public class Foobar {
#OneToOne
#JoinColumn(name="SELF_COLUMN_FOO", referencedColumnName = "FOREIGN_COLUMN_TO_JOIN")
public Foo foo;
#OneToOne
#JoinColumn(name="SELF_COLUMN_BAR", referencedColumnName = "FOREIGN_COLUMN_TO_JOIN")
public Bar bar;
}
This can be used where SELF_COLUMN is obviously the relevant column in the Foobar table, and FOREIGN_COLUMN_TO_JOIN would be single key in the other table you wish to join.
This will be useful where you want to have two (or more) attributes in a single class, but only one column to join on the foreign DB table. For example: An Employee may have a home phone number, cell number, and a work phone number. All are mapped to different attributes in the class, but on the database there's a single table of phone numbers and id's, and an identifier column, say VARCHAR(1) with 'H' or 'W' or 'C'. The real example would then be...
Tables:
PHONENUMBERS
PHONENUMBER_ID,
ACTUAL_NUMBER
EMPLOYEE
ID
HOMENUMBER VARCHAR(12),
CELLNUMBER VARCHAR(12),
WORKNUMBER VARCHAR(12)
public class Employee {
#OneToOne
#JoinColumn(name="HOMENUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone homeNum;
#OneToOne
#JoinColumn(name="CELLNUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone cellNum;
#OneToOne
#JoinColumn(name="WORKNUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone workNum;
}
As you can see, this would require multiple columns on the Entity's table, but allows you to reference a foreign key multiple times without throwing the 'Multiple writable mappings exist...' that you showed above. Not a perfect solve, but helpful for those encountering the same problem.
I have the following situation:
One Destination can have Many Aliases
Logically: I would like Destination to be the owner of this relationship, since if there was no destination, alias would not hold any meaning.
However, the database schema is like this:
DestinationAlias has idDestination as the Foreign Key and thus the #JoinColumn in hibernate annotation would be on DestinationAlias:
Destination:
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "mainCity")
public Set<DestinationAlias> getAliases() {
return aliases;
}
DestinationAlias:
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDDESTINATION", nullable=false)
public Destination getMainCity() {
return mainCity;
}
From this definition, DestinationAlias is the owner of this relationship since the mappedBy is an attribute on Destination class.
Does hibernate require me to follow the database schema and mark entity as the owner of the relationship or can it be done based on Logical reasons ?
Ownership affects how hibernate would model the underlying database tables. If you omit the mappedBy attribute, hibernate would generate a join-table (like for an M-M relationship) between Destination and DestinationAlias, instead of a simple join column. Other than that, I'm curious as to what your actual issue is here. Is this purely cosmetic, or are there functional issues in play for you here?
EDIT: as this seems to be a purely cosmetic issue, my advice is to just accept the Hibernate semantic. While I agree that it might appear counter-intuitive that Hibernate would call DestinationAlias the "owner", that is just the nomenclature Hibernate decided on. It's not unique either and it comes from the notion that the "owner" is where the join-column resides.
Don't waste time trying to force hibernate to conform to your definitions when you don't have to.
Let's say I have a Hibernate entity that declares a OneToMany relationship to a different entity:
#Entity
public class SomeEntity {
#OneToMany(fetch = FetchType.LAZY)
private List<OtherEntity> otherEntities = new LinkedList<OtherEntity>();
[...]
}
When mapping SomeEntity to the corresponding DTO, all I need are the IDs that identify OtherEntity as primary key (i.e., I am not actually interested in OtherEntity instances).
Does Hibernate support this pattern, i.e., only retrieving the IDs of entities referenced via a OneToMany relationship?
I cannot influence how SomeEntity is retrieved (i.e., I have an existing SomeEntity instance retrieved within te scope of the current Hibernate session), but let's assume that lazy loading has not yet taken place, so just retrieving the child objects' IDs (rather than the complete objects) would actually yield a performance benefit.
Well, if you only need the entities' ids and you want to be economical about it, when you get those entities from the database you should state in your query that you only want to get the ids of each entry, using projections, something like :
SELECT Entity.id as entity FROM Entity WHERE ...
This will return an array of objects of the same type as Entity's id field type.
You can try obtaining the primary key without accessing the entity itself (without otherEntities.get(0).getId()). To do this you can use the PersistenceUnitUtil class:
PersistenceUnitUtil#getIdentifier(yourEntity)
The PersistenceUnitUtil can be obtained from the EntityManagerFactory. So it could be something like:
EntityManager em = ...
PersistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil();
Unfortunately, I'm not aware if this will prevent the entity loading from occuring. However, just accessing the otherEntities collection or even obtaining references to each entity will not make the instance to be loaded; you need to invoke a method on the fetched entity in order to be sure it will be loaded.
You also might consider creating a #NamedQuery and return only the OtherEntity ID's.
HTH!
From hibernate reference, section 2.2.2.1.
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-property
Declare your columns as lazy initialized:
#Basic(fetch = FetchType.LAZY)
private String getYourProperty() {
}
You also need to disable proxies for your entity class and byte instrument it. There is an example here:
Making a OneToOne-relation lazy
You can use the below HQL as told in the documentation to establish this.
session.createQuery(select new OtherEntity(oe.id) OtherEntity oe
where oe.parentSomeEntity.someId = :someId).list();//also set someId.
Add a constructor in OtherEntity to set the id also there should be a mapping to SomeEntity in OtherEntity.
This HQL will give you a List<OtherEntity> with only id set in the bean.
I have the following existing DB schema, which I'd like to recreate with Java and plain JPA annotations (using hibernate as provider, so hibernate specific annotations would work as a last resort):
CREATE TABLE users (
user_id NUMBER NOT NULL -- pk
);
CREATE TABLE userdata_keys (
userdata_key_id NUMBER NOT NULL, -- pk
key VARCHAR2(128) NOT NULL
);
CREATE TABLE users_userdata (
user_id NUMBER NOT NULL, -- fk users.user_id
userdata_key_id NUMBER NOT NULL, -- fk userdata_keys.userdata_key_id
value VARCHAR2(256)
);
I've thus created the following classes and annotations:
class User {
#Id
Long id;
#OneToMany
Set<Userdata> userdata;
}
class UserdataKey {
#Id
Long id;
String key;
}
class Userdata {
String value;
#EmbeddedId
UserdataId userdataId;
}
#Embeddable
class UserdataId {
User user;
UserdataKey userdataKey;
}
I left out columnName attributes and other attributes of the entities here.
It does however not quite work as intended. If I do not specify a mappedBy attribute for User.userdata, hibernate will automatically create a table USERS_USERS_USERDATA, but as far as I've seen does not use it. It does however use the table which I specified for the Userdata class.
Since I'm rather new to Java and hibernate as well, all I do to test this currently is looking at the DB schema hibernate creates when persisting a few sample entries.
As a result, I'm entirely puzzled as to whether I'm doing this the right way at all. I read the hibernate documentation and quite a bunch of Google results, but none of them seemed to deal with what I want to do (composite key with "subclasses" with their own primary key).
The mappedBy attribute is mandatory at one of the sides of every bidirectional association. When the association is a one-to-many, the mappedBy attribute is placed ot the one- side (i.e. on the User's userdata field in your case).
That's because when an association is bidirectional, one side of the association is always the inverse of the other, so there's no need to tell twice to Hibernate how the association is mapped (i.e. which join column or join table to use).
If you're ready to recreate the schema, I would do it right (and easier), and use a surrogate auto-generated key in users_userdata rather than a composite one. This will be much easier to handle, in all the layers of your application.