While developing an Eclipse GEF application using an eclipselink implementation of JPA i have found an error that has been annoying me for a while:
I have three different classes:
The first one represents a variable contained in a model:
#Entity
public class Variable extends AbstractVariable{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#ManyToOne(cascade=CascadeType.ALL)
Model model;
//Setters, getters and the other functions.
}
And another subclass of the abstractvariant class, which is a variable which can hold a concatenation of variables.
#Entity
public class VariableList extends AbstractVariable{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#ManyToMany(cascade=CascadeType.ALL)
List<AbstractVariable> variables;
//Setters, getters and the other functions.
}
The second class, a gef editpart that can hold a variable value.
#Entity
public class VariableEditPart{
#Id
#Generated value
private int id;
/** Lots more of stuff */
VariableList vars;
//Setters, getters and the other functions.
}
And a last class with the gef model:
#Entity
public class Model{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#OneToMany(cascade=CascadeType.ALL)
List<Variable> availableVars;
#OneToMany(cascade=CascadeType.ALL)
List<VariableEditPart> editParts;
//Setters, getters and the other functions.
}
The issue here is that JPA creates a table for the relation variablelist-variable, and another relation with the editpart and the variablelist, so, as soon as I try to update the model at the database after some modifications, It tries automatically to delete the Variable, and ends up with a constraint violation error caused because the list of variables holded by the model still points to that variable (which by the way, I was not pretending to delete, and I've tested lots of differenst cascadeType's to avoid it without any luck...).
Thanks for your attention and be kind with my english, it's not my native language ;)
It seems you have a very interrelated model with everything referencing everything in cycles.
What are you doing exactly? When you remove the Variable, are you removing all references to it? You need to.
Related
PROBLEM: I have read-only data in a table. Its rows have no id - only composite key define its identity. I want it as a Value Object (in DDD terms) in my app.
RESEARCH: But if I put an #Embeddable annotation instead of #Entity with #Id id field, then javax.persistence.metamodel doesn't see it and says Not an embeddable on Metamodel metamodel.embeddable(MyClass.class);. I could wrap it with an #Entity class and autogenerate id, but this is not what I architectually intended to achieve.
QUESTION: Is JPA Embeddable a Value Object? Can Embeddable exist without a parent Entity and represent a Table?
There are many articles on the topic that show this is a real JPA inconvenience:
http://thepaulrayner.com/persisting-value-objects/
https://www.baeldung.com/spring-persisting-ddd-aggregates
https://paucls.wordpress.com/2017/03/04/ddd-building-blocks-value-objects/
https://medium.com/#benoit.averty/domain-driven-design-storing-value-objects-in-a-spring-application-with-a-relational-database-e7a7b555a0e4
Most of them suggest solutions based on normalised relational database, with a header-entity as one table and its value-objects as other separate tables.
My frustration was augmented with the necessity to integrate with a non-normalized read-only table. The table had no id field and meant to store object-values. No bindings with a header-entity table. To map it with JPA was a problem, because only entities with id are mapped.
The solution was to wrap MyValueObject class with MyEntity class, making MyValueObject its composite key:
#Data
#Entity
#Table(schema = "my_schema", name = "my_table")
public class MyEntity {
#EmbeddedId MyValueObject valueObject;
}
As a slight hack, to bypass JPA requirements for default empty constructor and not to break the immutability of Value Object, we add it as private and sacrifice final modifier for fields. Privacy and absence of setters conforms the initial DDD idea of Value Object:
// #Value // Can't use, unfortunately.
#Embeddable
#Immutable
#AllArgsConstructor
#Getter
#NoArgsConstructor(staticName = "private") // Makes MyValueObject() private.
public class MyValueObject implements Serializable {
#Column(name = "field_one")
private String myString;
#Column(name = "field_two")
private Double myDouble;
#Transient private Double notNeeded;
}
Also there is a handful Lombok's #Value annotaion to configure value objects.
I have an entity:
#Entity
public class Test {
#Embedded
Content content;
// getters setters..
}
This contains an embedded class as you can see:
#Embeddable
public class Content {
#OneToOne
Person person;
#Embedded
Language language;
// getters setters..
}
This contains again an embeddable. 2 times nested embeddable
#Embeddable
public class Language {
String format;
#OneToOne
IdentifierCode identifierCode;
// getters setters..
}
When using the automatic schema generation feature of JPA all columns are generated in the correct way.
I use the #Data annotation on each #Entity and #Embeddable to generate getters, setters, constructors, etc..
When starting the application server (EAP 7), I notice this warning in the logs:
HHH015011: Unable to locate static metamodel field :
org.package.Language_#identifierCode; this may or may not indicate a
problem with the static metamodel
Indeed, when opening the metamodel class Language_; no identifierCode column reference is present:
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Language.class)
public abstract class Language_ {
public static volatile SingularAttribute<Language, String> format;
}
I don't see what I'm doing wroing. Is it not possible to use #OneToOne in a nested #Embeddable? The metamodel Content_ correctly generates the singular attribute for person!
It seems when using multiple nested embeddables, something goes wrong. When using only one level of embeddables, it works.
I tried other stuff:
Adding Access.Field on the class. Nothing happens.
Instantiation the #Embedded class, like #Embedded Language language = new Language(). Nothing happens.
Replaced the #OneToOne with #ManyToOne. Nothing happens.
This sounds like a bug in your JPA provider, which you should report to them.
The JPA provider I use (DataNucleus) creates a
public static volatile SingularAttribute<Language, mydomain.model.IdentifierCode> identifierCode;
One option you have is to just use the datanucleus-jpa-query.jar in your CLASSPATH to generate the static metamodel and use those generated classes with your existing provider, alternatively use it for persistence too.
I have a problem to integrate Hibernate Search in existing project with hundreds of entities but at least half of entities use #IdClass annotation as composed key. Can I solve the problem using the annotation #IdClass?
I also read this post Hibernate search and composed keybut I have not managed to solve my problem.
I have the following example:
entity class:
#Entity
#Table(name="FAKVS_DB")
#IdClass(value=PK_FAKVS_DB.class)
#Audited
#Indexed
public class FAKVS_DB implements Serializable {
#Id
#Column(name="Key_FAM", length=10, nullable=false)l
private String keyFam;
#Id
#Column(name="Komponentennr", nullable=false)
private Integer komponentenNr;
#Id
#Column(name="Hinweis", nullable=true, length=4)
private String hinweis;
//getters and setters
}
and composed key:
public class PK_FAKVS_DB implements Serializable {
private String keyFam;
private Integer komponentenNr;
private String hinweis;
//getters and setters
}
The error that occurs is:
HSEARCH000058: HSEARCH000212: An exception occurred while the MassIndexer was transforming identifiers to Lucene Documents
java.lang.ClassCastException: package.entities.module.fi.pk.PK_FAKVS_DB cannot be cast to java.lang.Integer
at org.hibernate.type.descriptor.java.IntegerTypeDescriptor.unwrap(IntegerTypeDescriptor.java:36)
at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:63)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:90)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:286)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:281)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1995)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1966)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1901)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1839)
at org.hibernate.loader.Loader.doQuery(Loader.java:910)
If I can not use #IdClass annotation can you tell me what are the alternatives?
Thank you very much in advance.
An alternative is to add a new property to be used as Id by Hibernate Search. You can mark this with #DocumentId to have the Hibernate Search engine treat the alternative property as the identifier in the index.
You will need to ensure that this new property is unique of course; this can typically done by generating a String from the real id. You probably want to annotate the new getter with #Transient so that it doesn't get persisted in the database.
I have this #ElementCollection mapping so i could bring a legacy table with no unique id to work:
#Entity #Table(...)
#Inheritance(...) #DiscriminatorColumn(...)
class Notification {
#Id
#Column(name="NOTIFICATION_ID")
private BigInteger id;
}
#Entity
#DiscriminatorValue(...)
class SomeNotification extends Notification {
#ElementCollection
#CollectionTable(name="LEGACY_TABLE", joinColumns=#JoinColumn(name="NOTIFICATION_ID"))
private Set<NotificationInfo> someInformations;
}
#Embeddable
class NotificationInfo { // few columns }
I really can't touch the structure of LEGACY_TABLE, and now i am facing this:
#Entity
#DiscriminatorValue(...)
class SpecialNotification extends Notification {
// ? This is not a Collection, and it can't be a ManyToOne or OneToOne
// since there is no ID declared on NotificationInfo.
private NotificationInfo verySpecialInformation;
}
I know this is not supported by default, but i am fine to implement a Customizer to make it work with EclipseLink. The point is that for SpecialNotification instances, there will be only up to one NotificationInfo associated, instead of many, that is the case of SomeNotification.
Any thoughts about where i could start in the Customizer?
Thank you!
I'm not sure this will work, but it's worth a shot. Try a combination of #SecondaryTable and #AttributeOverride
#Entity
#SecondaryTable(name="LEGACY_TABLE",
pkJoinColumns=#PrimaryKeyJoinColumn(name="NOTIFICATION_ID"))
#DiscriminatorValue(...)
class SpecialNotification extends Notification {
...
#Embedded
#AttributeOverrides({
#AttributeOverride(name="someField", column=#Column(table = "LEGACY_TABLE", name="SOME_FIELD")),
#AttributeOverride(name="someOtherField", column=#Column(table = "LEGACY_TABLE", name="SOME_OTHER_FIELD"))
})
private NotificationInfo verySpecialInformation;
...
}
UPDATE
Since #SecondaryTable by default makes an inner join, which may not be desired, it can be worked around with vendor specific APIs.
If you use Hibernate (which you don't, judging by the question tags, but nevertheless), it can be done with #org.hibernate.annotations.Table, by setting optional = true.
With EclipseLink, you should make use of #DescriptorCustomizer and DescriptorQueryManager#setMultipleTableJoinExpression, you can find a (not spot-on, but close enough) code example here.
the question and problem is pretty simple, though annoying and I am looking for a global solution, because it's application-wide problem for us.
The code below is really not interesting but I post it for clarification!
We use PostgreSQL database with JPA 2.0 and we generated all the facades and entities, of course we did some editing but not much really.
The problem is that every entity contains a Collection of its children, which however (for us only?) is NOT updated after creation a children element.
The objects are written to database, you can select them easily, but what we really would like to see is the refreshed collection of children in parent object.
Why is this happening? If we (manually) refresh the entity of parent em.refresh(parent) it does the trick but it would mean for us a lot of work in Facades I guess. But maybe there is no other way?
Thanks for support!
/* EDIT */
I guess it has to be some annotation problem or cache or something, but I've already tried
#OneToMany(mappedBy = "idquestion", orphanRemoval=true, fetch= FetchType.EAGER)
and
#Cacheable(false)
didn't work properly.
/* EDIT */
Some sample code for understanding.
Database level:
CREATE TABLE Question (
idQuestion SERIAL,
questionContent VARCHAR,
CONSTRAINT Question_idQuestion_PK PRIMARY KEY (idQuestion)
);
CREATE TABLE Answer (
idAnswer SERIAL,
answerContent VARCHAR,
idQuestion INTEGER,
CONSTRAINT Answer_idAnswer_PK PRIMARY KEY (idAnswer),
CONSTRAINT Answer_idQuestion_FK FOREIGN KEY (idQuestion) REFERENCES Question(idQuestion)
);
Than we have generated some Entities in Netbeans 7.1, all of them look similar to:
#Entity
#Table(name = "question", catalog = "jobfairdb", schema = "public")
#XmlRootElement
#NamedQueries({ BLAH BLAH BLAH...})
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "idquestion", nullable = false)
private Integer idquestion;
#Size(max = 2147483647)
#Column(name = "questioncontent", length = 2147483647)
private String questioncontent;
#OneToMany(mappedBy = "idquestion", orphanRemoval=true)
private Collection<Answer> answerCollection;
Getters... setters...
We use (again) generated facades for them, all implementing AbstractFacade like:
public abstract class CCAbstractFacade<T> {
private Class<T> entityClass;
public CCAbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
The father entity is updated automatically if you use container managed transactions and you fetch the collection after the transaction is complete. Otherwise, you have to update yourself the collection.
This article explains in detail this behaviour: JPA implementation patterns: Bidirectional associations
EDIT:
The simplest way to use Container Managed Transactions is to have transaction-type="JTA" in persistence.xml and use Container-Managed Entity Managers.
You seem to be setting the ManyToOne side, but not adding to the OneToMany, you have to do both.
In JPA, and in Java in general you must update both sides of a bi-directional relationship, otherwise the state of your objects will not be in sync. Not doing so, would be wrong in any Java code, not just JPA.
There is no magic in JPA that will do this for you. EclipseLink does have a magic option for this that you could set through a customizer (mapping.setRelationshipPartnerAttributeName()), but it is not recommended, fixing your code to be correct is the best solution.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Object_corruption.2C_one_side_of_the_relationship_is_not_updated_after_updating_the_other_side