Hibernate JPA: mappedBy reference exception - java

I want to map the following classes with Hibernate JPA:
My code looks like this:
#Entity
public class Grid{
#Id
#GeneratedValue
private Long id;
#Column(unique=true)
private String name;
private String location;
private BigDecimal costsPerCPUMinute;
#OneToMany(mappedBy="grid")
private List<Membership> mem;
public List<Membership> getMem() {
return mem;
}
public void setMem(List<Membership> mem) {
this.mem = mem;
}
#Entity
public class User extends Person{
#Column(nullable=false, unique=true)
private String username;
#Column(length=16,columnDefinition="BINARY(16)")
private byte[] password;
#OneToMany(mappedBy="user")
private List<Membership> mem;
public List<Membership> getMem() {
return mem;
}
public void setMem(List<Membership> mem) {
this.mem = mem;
}
#SuppressWarnings("serial")
#Entity
public class Membership implements Serializable{
private Date registration;
private Double discount;
#Id
#ManyToOne
private Grid grid;
#Id
#ManyToOne
private User user;
public Grid getGrid() {
return grid;
}
public void setGrid(Grid grid) {
this.grid = grid;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
Unfortunately, I get the following Exception:
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: dst1.model.Membership.grid in dst1.model.Grid.mem
As far as I understand the message, grid cannot be found in Membership. But as you can see in de code, there definitly is a variable named grid in the Membership class.
Does anybody has an idea whats going wrong?
Update: As suggested in the comments, I also tried to change the Membership Class by using IDClass or EmbeddedID. The EmbeddedID version looks like this:
#SuppressWarnings("serial")
#Entity
public class Membership implements Serializable{
private Date registration;
private Double discount;
#EmbeddedId
private MembershipPK membershipPK;
public Membership(){};
public MembershipPK getMembershipPK() {
return membershipPK;
}
public void setMembershipPK(MembershipPK membershipPK) {
this.membershipPK = membershipPK;
}
#SuppressWarnings("serial")
#Embeddable
public class MembershipPK implements Serializable{
#ManyToOne
private Grid grid;
#ManyToOne
private User user;
public Grid getGrid() {
return grid;
}
public void setGrid(Grid grid) {
this.grid = grid;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Unfortunately, I still get the same exception.
Update 2: I will rewrite all three classes from scratch tomorrow evening and update this post if that changes anything.

You should be able to use something like
#Embeddable
public class MembershipId
{
protected Grid grid;
protected User user;
}
#Entity
public class Membership {
#EmbeddedId
MembershipId id;
}
#Entity
public class User {
#OneToMany(mappedBy="id.user")
private Set<Membership> memberships = new HashSet<Membership>();
}

From the top of my head: shouldn't this be rather
public class MembershipId implements Serializable {
private Grid grid;
private User user;
// immutable constructor, getters, equals, and hashCode
}
#Entity
#IdClass(MembershipId.class)
public class Membership implements Serializable {
#Id #ManyToOne
private Grid grid;
#Id #ManyToOne
private User user;
// rest of class
}
Edit: What the exception is telling you is that your Grid class has a field named mem and that the entity represented by this field needs a grid field, but doesn't have one. Here is where your Grid.mem needs a grid field:
#Entity
public class Grid{
...
#OneToMany(mappedBy="grid")
private List<Membership> mem;
This mapping can only work if there is a property grid in Membership.class. If you hide the grid inside the IdClass, Grid.mem can't find it. You might try this:
#Embeddable
public class MembershipId implements Serializable {
private Grid grid;
private User user;
// immutable constructor, getters, equals, and hashCode
}
#Entity
public class Membership implements Serializable {
#EmbeddedId
private MembershipId id;
#ManyToOne
private Grid grid;
#ManyToOne
private User user;
// rest of class
}

Related

Spring data neo4j - polymorphic children collection

I have following classes:
public interface Label {
String getValue();
}
#Node
#Data
public class SimpleLabel implements Label {
#Id
#GeneratedValue
private Long id;
private String value;
#Relationship(value = "JE")
private Set<SimpleLabel> labels = new HashSet<>();
public void addLabel(SimpleLabel label){
labels.add(label);
}
}
#Node
#Data
public class HyperLabel implements Label {
#Id
#GeneratedValue
private Long id;
#Relationship(value = "JE")
private Set<Label> labels = new HashSet<>();
public void addLabel(Label label){
labels.add(label);
}
#Override
public String getValue() {
return labels.stream().map(Label::getValue).collect(Collectors.joining("; "));
}
}
and this is the query I'm using:
#Query("MATCH (h:HyperLabel)-[r:JE]-(s:SimpleLabel) WHERE ID(h)=$id RETURN h,COLLECT(r),COLLECT(s)")
Optional<HyperLabel> getById(Long id);
The problem, I'm having is that labels collection that is returned by query is empty. But if I make a slight change in the code of HyperLabel class (change Set<Label> to Set<SimpleLabel>), then it works.
Is there any way to make it work with Label interface, since children of HyperLabel can be both HyperLabel and SimpleLabel instances?

Java - JPA Repeatable #Embedded annotations

All tables in our shop have the same set of identical audit columns(system, user, terminal, etc)
So instead of copying the same columns in every class I tried to use the embedded annotation
#Entity
#Table(name="PRODUCT")
public class ProdEntity implements Serializable{
private long prod;
//set/get code
private CommonJrnFields jrn;
#Embedded
public CommonJrnFields getJrn() {return this.jrn;}
public void setJrn(CommonJrnFields jrn) {this.jrn = jrn;}
private OrdEntity ord;
#OneToOne(mappedBy="prod")
public OrdEntity getOrd() {return this.ord;}
public void setOrd(OrdEntity ord) {this.ord = ord;}
}
#Entity
#Table(name="ORDERS")
#NamedQuery(name="OrdEntity.findAll", query="SELECT o FROM OrdEntity o")
public class OrdEntity extends ProdEntity implements Serializable{
private long ord;
//set/get code
private CommonJrnFields jrn;
#Embedded
public CommonJrnFields getJrn() {return this.jrn;}
public void setJrn(CommonJrnFields jrn) {this.jrn = jrn;}
private ProdEntity prod;
#OneToOne(mappedBy="ord")
public ProdEntity getProd () {return this.prod;}
public void setProd(ProdEntity prod) {this.prod = prod;}
}
#Embeddable
public class CommonJrnFields {
private String user;
private String system;
//set/get code
}
As a result embedded columns of extended class overrides base class and named query returns
ProdEntity.prod
OrdEntity.ord
OrdEntity.system
OrdEntity.user
instead of
ProdEntity.prod
ProdEntity.system
ProdEntity.user
OrdEntity.ord
OrdEntity.system
OrdEntity.user
How to fix it?
Please do not offer the #AttributeOverrides solution.
I'm working with almost 100 tables and do attribute override in each class for 8 common columns specifying table="" does not make any sense. It would be much faster just to cut/paste the embeddable code into all entities if there is no other solutions.

Saving to Neo4j removing values

I am using a typical User -> Role relationship with my application. I am taking advantage of Neo4j's ability to add metadata on the relationship through the RelationshipEntity annotation. For some unexplained reason the Role's properties are being 'nulled' out when I persists my relationship.
Here's my User
public class Person {
#GraphId Long id;
private String name;
#RelatedToVia(type="HAS_ROLE")
#Fetch
private Set<UserRoleRelationship> roles = new HashSet<UserRoleRelationship>();
public Person() {}
public Person(String name) { this.name = name; }
}
Role
#NodeEntity
public class Role {
#GraphId Long id;
private RoleType roleType;
#SuppressWarnings("unused")
private String roleName;
private #Fetch Set<Privilege> defaultPrivileges;
}
RelationshipEntity
#RelationshipEntity(type="HAS_ROLE")
public class UserRoleRelationship {
#GraphId Long id;
#StartNode private Person person;
#EndNode private Role role;
private List<Privilege> privileges = new ArrayList<Privilege>();
}
RoleType (Used in Role)
public enum RoleType {
ADMIN("Administrator", Arrays.asList(new Privilege(PrivilegeType.PRIV1.name()),
new Privilege(PrivilegeType.PRIV2.name()),
new Privilege(PrivilegeType.PRIV3.name()),
new Privilege(PrivilegeType.PRIV4.name()))),
USER("User", Arrays.asList(new Privilege(PrivilegeType.PRIV1.name()))),
private String name;
private Set<Privilege> defaultPrivileges = new HashSet<Privilege>();
private RoleType(String name, List<Privilege> privileges){
this.name=name;
this.defaultPrivileges=new HashSet<Privilege>(privileges);
}
public String getName() {
return name;
}
public Set<Privilege> getDefaultPrivileges() {
return defaultPrivileges;
}
}
When populating the relationship with a User and Role, all the data is set. However when I persists it the Role's data is now null.
// Before Save
UserRoleRelationship [id=null, person=Person [id=26, name=TestUser, roles=1], **role=Role [id=27, roleType=ADMIN, defaultPrivileges=[PRIV4, PRIV1, PRIV2, PRIV3]]**]
// After Save
UserRoleRelationship [id=6, person=Person [id=26, name=TestUser, roles=0], **role=Role [id=27, roleType=null, defaultPrivileges=null]**]
Any ideas as to why this is occurring to my Role Object?
Also, here are my Repos
public interface PersonRepository extends CrudRepository<Person, String> {
Person findByName(String name);
}
public interface RoleRepository extends CRUDRepository<Role> {
Role findByRoleType(RoleType rt);
Role findByRoleName(String name);
}
public interface UserRoleRepository extends CrudRepository<UserRoleRelationship, String> {}
It repopulates the UserRoleRelationship after saving.
As you don't have a #Fetch annotation on neither the start nor end-node it only loads them in a shallow fashion.
I don't recommend to add #Fetch there because it can easily load your whole graph, so I'd probably use
template.fetch(rel.person);
template.fetch(rel.role);

Ebean EmbeddedId mapping column to ManyToOne relation

I'm facing a problem with Ebean when trying to create Composed Keys (EmbeddedId).
This is a draft of what I have:
#Entity public class EntityA extends Model{
#Id
private String ID;
#OneToMany
private List<EntityB> listEntitesB;
public EntityA(){
ID = UUID.randomUUID();
}
}
#Entity public class EntityB extends Model{
#EmbeddedId
private EntityB_PK ID;
#ManyToOne
#JoinColumn(name="entityA_fk", referencedColumnName="listEntitiesB")
private EntityA entityA;
public EntityB(String entityB_ID){
ID = new EntityB_PK(UUID.randomUUID(), entityB_ID);
}
}
#Embeddable public class EntityB_PK{
private String entityB_ID;
private String entityA_FK_ID;
public EntityB_PK(String entB_ID, String entA_FK_ID){
entityB_ID = entB_ID;
entityA_FK_ID = entA_FK_ID;
}
}
Note: I'm using Ebean 4.1.4 with Java 1.6.
So, this code works well, but there is a perk, which I'm trying to solve - the resultant table in the database looks like this:
entityB_ID [primary]
entityA_FK_ID [primary]
entityA_fk
As you can see that last column is redundant considering the "entityA_FK_ID" column.
What I would like to have?
I would like to be able to tell Ebean to use the column "entityA_FK_ID" for the association #ManyToOne instead of creating it's own column.
To solve this problem we have to:
Map EntityB.entityA to the same column as EntityB.ID.entityA_FK_ID
set 'insertable' and 'updateable' attributes of EntityB.entityA #JoinColumn annotation
Override setter of EntityB.entityA
Here is the code:
EntityA.java:
#Entity
public class EntityA extends Model {
#Id
private String ID;
#OneToMany(mappedBy="entityA")
public List<EntityB> listEntitesB;
public static Finder<String,EntityA> find = new Finder<String,EntityA>(
String.class, EntityA.class
);
public EntityA() {
ID = UUID.randomUUID().toString();
}
public String getID() {
return ID;
}
}
EntityB.java:
#Entity
public class EntityB extends Model {
#EmbeddedId
private EntityB_PK ID;
#ManyToOne
#JoinColumn(name = "entityA_fk_id", insertable = false, updatable = false)
private EntityA entityA;
public EntityA getEntityA() {
return entityA;
}
public void setEntityA(EntityA aEntityA) {
entityA = aEntityA;
ID.entityA_FK_ID = aEntityA.getID();
}
public EntityB(String entityB_ID){
ID = new EntityB_PK(UUID.randomUUID().toString(), entityB_ID);
}
public String getID() {
return ID.entityB_ID;
}
}
EntityB_PK.java:
#Embeddable
public class EntityB_PK implements Serializable {
public String entityB_ID;
#Column(name="entityA_fk_id")
public String entityA_FK_ID;
public EntityB_PK(String entB_ID, String entA_FK_ID){
entityB_ID = entB_ID;
entityA_FK_ID = entA_FK_ID;
}
#Override
public int hashCode() {
return entityB_ID.length() + entityA_FK_ID.length();
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
EntityB_PK b = (EntityB_PK)obj;
if(b==null)
return false;
if (b.entityB_ID.equals(entityB_ID) && b.entityA_FK_ID.equals(entityA_FK_ID)) {
return true;
}
return false;
}
}

Play Framework: No #javax.persistence.Id field found in class

I have this Play Model class that I'm trying to modify an object of, and when I want to save it, I get the following exception:
java.lang.RuntimeException: No #javax.persistence.Id field found in class [class models.Contact]
at play.db.ebean.Model._idAccessors(Model.java:39)
at play.db.ebean.Model._getId(Model.java:52)
The class:
#Entity
public class Contact extends Model implements Person {//, Comparable<Contact>{
private Long id;
private Client client;
#Required
private String email;
private String profil_picture;
private Boolean active = new Boolean(true);
private Boolean favorite = new Boolean(false);
#Transient
private Boolean profile_pic_url_init = new Boolean(false);
#Id
#GeneratedValue
public Long getId() {
return id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="client_id")
public Client getClient(){
return client;
}
public void setClient(Client client){
this.client= client;
}
#Column
public Boolean getFavorite() {
return favorite;
}
public void setFavorite(Boolean is_favorite) {
this.favorite = is_favorite;
}
....
}
The code calling the save() method:
List<Contact> contacts_list = current_client.getContacts();
for (Contact c : contacts_list) {
c.setFavorite(false);
c.save();
}
The class actually has an #Id annotation, so any guesses of why this doesn't work? I tried looking it up on google, but couldn't find much about this error. Thanks in advance!
Move #Id annotation to id field instead of its getter.

Categories

Resources