Is it possible/supported to have a #javax.persistence.Id or #EmbeddedId on a simple property (i.e. no composite class) nested in an inner (#Embedded) class?
The structure looks like this:
{
"something": {
"id": 123456789,
...
},
...
},
There is no many-to-anything relationship involved in my case.
Also I have no control over the class/type/structure above.
I tried following:
#Entity
class MyEntity {
#Embedded
Something something;
#Embeddable
class Something {
// #Id
#EmbeddedId
Long id;
...
}
...
}
...and several other variations, but nothing seems to work. Usually I end up with an exception about my entity not having an identifier specified.
I would expect Hibernate to go through the #Embedded properties recursively and detecting the nested #Id/EmbeddedId eventually, but that does not seem to happen.
Do I need to replace the simple Long id with a composite id/class? Not sure it would even work but I would prefer avoiding that.
Also I would like to stick with #Access(AccessType.FIELD) which disqualifies the workaround of having #Id on some transient property directly in MyEntity, which would be pointing at MyEntity.Something.Id field.
I am looking for a clean solution that does not another level of complexity to the mapping please.
My sub-optimal solution meanwhile is not treating the entity.something.id as an #Id at all, having my own #Id added as entity.id instead, and dealing with the consequences later on in the process.
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 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.
I have an entity looks like this.
#Entity
#XmlRootElement
class Parent {
// No getters nor setters for 'children'
// Don't attack via reflection!
#OneToMany(cascade = {CascadeType.REMOVE}, mappedBy = "parent") // lazy, huh?
#XmlTransient
private Collection<Child> chilren; // MILLIONS OF THEM, say.
}
I mapped children just for Criteria Query.
#StaticMetamodel(Parent.class)
class Parent_ {
public static volatile CollectionAttribute<Parent, Child> children;
}
My question is, is it safe to map those children this way? Is it possible that chilren fetched from DB within a Parent for any case?
If you never want to access the relationship, I would not map it. You should be able to define most queries using the ManyToOne back instead of the OneToMany.
If you are using EclipseLink, you can also define query keys for relationships that are only used in queries,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query_Keys
A LAZY OneToMany that you never access is probably safe, but you need to be very careful you don't do anything that will cause it to instantiate. The cascade remove is probably a bad idea, as it will cause it to be instantiated on remove.
I'm using Morphia for MongoDB with Stripes Framework.
Let us assume I have two entities, Car (which describes a specific car, say some particular 1984 Honda Accord) and CarType (which specifies all Honda Accords of that kind):
The most natural way to model this seems:
#Entity
class Car {
#Id private String id; // VIN
private Date purchaseDate;
private Color color;
#Reference private CarType type;
// ..
}
#Entity
class CarType {
#Id private String id;
private String manufacturerId;
private float engineDisplacement;
// ..
}
This works, but is inefficient, as CarType is looked up from DB every time a Car is loaded. I would like to cache car types in memory, as they change rarely. Persistence frameworks like GORM and Hibernate would allow that out of the box, but I'm not sure how to do it under Morphia (there is a feature request raised for that).
I'd like to keep the reference to CarType, as just storing a String carTypeId would complicate the views and everything else too much.
So I thought I could do something like this:
#Entity
class Car {
#Id private String id; // VIN
private Date purchaseDate;
private Color color;
private String typeId;
#Transient private CarType type;
#Transient private CarService service = new CarServiceImpl();
public void setTypeId() {
this.typeId = typeId;
updateTypeReference();
}
#PostLoad void postLoad() {
updateTypeReference();
}
private void updateTypeReference() {
type = service.findTypeById(typeId);
}
// ..
}
class CarServiceImpl implements CarService {
#CacheResult CarType findCarTypeId(String typeId) {
datastore.get(CarType.class, typeId);
}
// ..
}
Which works and does what I want, but:
Does seem like a hack
I'd to inject the service instead using Guice, but cannot figure out how, although I have overall dependency injection working in Stripes ActionBeans.
So I'd like to either:
Learn how to inject (preferably, Guice) services into Morphia entities
or
Learn how to otherwise properly do caching for referenced entities in Morphia
or
If all else fails, switch to some other MongoDB POJO mapping approach which supports caching. But I really like Morphia so I'd rather not.
Another common approach would be to embed the CarType in each Car. That way you would only have to fetch a single entity.
Trade-offs:
You'll need an update logic for all duplicated CarTypes. Since you said that they hardly change, this should be fine performance-wise.
Duplicated data requires additional disk-space and the working set in RAM gets bigger as well.
You'll need to evaluate how this works out for your data, but data duplication to make reads faster is quite a common approach...
Since I didn't think of a better solution I am doing a #PostLoad event handler which gets the datastore class from a static variable, and can then look up the Referenced entity.
That seems like a hack and requires the datastore service to be thread-safe, but it works for me.
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