Updating a ManyToMany relationship to include a new field - java

So, I've got an existing ManyToMany relationship set up in my spring application. It appears that I made a mistake by setting this up using the #ManyToMany annotation, because now I need to add a field to the join table, and this does not appear to be an easy feat.
My structure is shipments and products. The shipment table stores information about who the shipment was sent to, what date it was sent, etc. The product table stores information about the product, who makes it, description, size, etc.
What I failed to consider when building this out was, I will need to track quantity of product shipped when I create a shipment, which should be done on the join table.
I've been working along with this example: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/
UPDATE:
I've been working through the example above and have run into an issue with infinite recursive calls between the product and shipment tables. My structure is as follows:
ShipmentProductID.java:
// Package and Imports here
#Embeddable
public class ShipmentProductId
implements Serializable {
#Column(name = "product_id")
private Long productId;
#Column(name = "shipment_id")
private Long shipmentId;
private ShipmentProductId() {}
public ShipmentProductId(
Long productId,
Long shipmentId) {
this.productId = productId;
this.shipmentId = shipmentId;
}
// Getters and Setters here
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProductId that = (ShipmentProductId) o;
return Objects.equals(productId, that.productId) &&
Objects.equals(shipmentId, that.shipmentId);
}
#Override
public int hashCode() {
return Objects.hash(productId, shipmentId);
}
}
ShipmentProduct.java:
// Package and Imports here
#Entity(name = "ShipmentProduct")
#Table(name = "shipment_product")
public class ShipmentProduct {
#EmbeddedId
private ShipmentProductId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("productId")
private Product product;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("shipmentId")
private Shipment shipment;
#Column(name = "created_on")
private Date createdOn = new Date();
private ShipmentProduct() {}
public ShipmentProduct(Product product, Shipment shipment) {
this.product = product;
this.shipment = shipment;
this.id = new ShipmentProductId(product.getId(),
shipment.getId());
}
// Getters and Setters here
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProduct that = (ShipmentProduct) o;
return Objects.equals(product, that.product) &&
Objects.equals(shipment, that.shipment);
}
#Override
public int hashCode() {
return Objects.hash(product, shipment);
}
}
Product.java:
// Package and Imports here
#Entity
#Data
#Cache( usage = CacheConcurrencyStrategy.READ_WRITE )
public class Product extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#JsonIgnoreProperties("products")
// Have tried #JsonIgnore as well
#OneToMany(
mappedBy = "product",
orphanRemoval = true
)
private List<ShipmentProduct> shipments = new ArrayList<>();
#NotNull
private Integer quantity;
public boolean isAssociated(Client client){
if( this.client == null || this.client.getId() == null ||
client == null || client.getId() == null ) return
false;
return this.client.getId() == client.getId();
}
public boolean isAssociated(Expression expression){
if( this.expression == null || this.expression.getId() == null
||
expression == null || expression.getId() == null )
return false;
return this.expression.getId() == expression.getId();
}
public void addShipment(Shipment shipment) {
ShipmentProduct shipmentProduct = new ShipmentProduct(this,
shipment);
shipments.add(shipmentProduct);
shipment.getProducts().add(shipmentProduct);
}
public Set<Shipment> getAllShipments(){
Set<Shipment> shipmentList = new HashSet<>();
for (ShipmentProduct shipmentProduct : shipments) {
shipmentList.add(shipmentProduct.getShipment());
}
return shipmentList;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(id, product.id);
}
#Override
public String toString(){
return "";
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
Shipment.java:
// Package and Imports here
#Entity
#Data
#ToString(exclude = {"products", "contacts"})
#EqualsAndHashCode(exclude = {"products", "contacts"})
public class Shipment extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonIgnoreProperties("shipments")
#OneToMany(
mappedBy = "shipment",
orphanRemoval = true
)
private List<ShipmentProduct> products = new ArrayList<>();
public Set<Product> getAllProducts(){
Set<Product> productList = new HashSet<>();
for (ShipmentProduct shipmentProduct : products) {
productList.add(shipmentProduct.getProduct());
}
return productList;
}
public void addProduct(Product product) {
ShipmentProduct shipmentProduct = new ShipmentProduct(product,
this);
products.add(shipmentProduct);
product.getShipments().add(shipmentProduct);
}
public void removeProduct(Product product) {
for (Iterator<ShipmentProduct> iterator = products.iterator();
iterator.hasNext(); ) {
ShipmentProduct shipmentProduct = iterator.next();
if (shipmentProduct.getShipment().equals(this) &&
shipmentProduct.getProduct().equals(product)) {
iterator.remove();
shipmentProduct.getProduct().getShipments().remove(shipmentProduct);
shipmentProduct.setShipment(null);
shipmentProduct.setProduct(null);
}
}
}
public Optional<Product> getProductById(Long productId){
Optional<ShipmentProduct> shipmentProduct =
products.stream().filter(product ->
product.getId().equals(productId)).findFirst();
return productId == null ? Optional.empty() :
Optional.of(shipmentProduct.get().getProduct());
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shipment shipment = (Shipment) o;
return Objects.equals(id, shipment.id);
}
#Override
public String toString(){
return "";
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
It seems like I'm getting close, as this appears to be working aside from creating an infinitely large JSON object. I've tried all sorts of combinations of EAGER vs LAZY and JsonIgnore and JsonIgnoreProperties. Any thoughts on how to resolve this? My best guess is some interaction with Lombok, but I have not been able to figure this out.

Looks like I finally figured this out... I removed the following methods:
getAllProducts()
getAllShipments()
and replaced them with:
allProducts()
allShipments()
Having them as getters was always adding them to my return object, and they were not being cut off by #JsonIgnore, or anything else.
Next, I updated ShipmentProduct.java and added #JsonIgnore to both shipment and product, while removing #JsonIgnore and/or #JsonIgnoreProperties from Shipment.java and Product.java.
Then, in order to not receive errors when utilizing allProducts() or allShipments(), I added this to my application.properties file: spring.jackson.serialization.fail-on-empty-beans=false
Once this was all complete, I was also able to keep lombok.
Hopefully this helps somebody else in a similar situation. Also, if anybody has additional constructive criticism, please let me know!

You can keep #ManyToMany annotation, just add the joining table in your db and map it:
#JoinTable(
name = "joining_table",
joinColumns = #JoinColumn(
name = "this_id_in_jt",
referencedColumnName = "this_id"
),
inverseJoinColumns = #JoinColumn(
name = "other_id_in_jt",
referencedColumnName = "other_id"
)
)
#ManyToMany
private List<Other> others;

Related

Using Hibernate and TreeSet does not work the remove() and contains() methods

I want to have a sorted set by age;
The method compareTo() in this case works fine but the problem is that remove() and contians() methods returns always false;
INTERESTING: In case I uncomment the lines form compareTo() method, remove() and contains() methods works fine; but I want to use the other field as sorting.
Does someone have any idea why does not work properly; Found old Hibernate issue: https://hibernate.atlassian.net/browse/HHH-2634;
is this already fixed?
Bellow are the used classes:
#Entity(name = "CAMPAIGN")
public class Campaign implements Identifiable, Serializable {
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#OneToMany(mappedBy = "campaign", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#OrderBy("age ASC")
private SortedSet<MailingAddress> mailingAddresses = new TreeSet<>();
...
public void removeMailingAddress(MailingAddress mailingAddress) {
this.mailingAddresses.remove(mailingAddress);
//this.mailingAddresses.contains(mailingAddress);
mailingAddress.setCampaign(null);
}
}
And
#Entity(name = "MAILING_ADDRESS")
public class MailingAddress implements Identifiable, Comparable, Serializable {
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#ManyToOne
#JoinColumn(name = "CAMPAIGN_ID")
private Campaign campaign;
#Column(name = "AGE")
private Integer age;
#Override
public int compareTo(Object o) {
if (o == null) {
return 1;
}
if (!(o instanceof MailingAddress)) {
throw new ClassCastException("Cannot compare MailingAddress with " + o.getClass());
}
MailingAddress o1 = (MailingAddress) o;
int comparison;
// comparison for id
/*comparison = compareFields(this.id, o1.id);
if (comparison != 0) {
return comparison;
}*/
// comparison for ageBand
comparison = compareFields(this.age, o1.age);
if (comparison != 0) {
return comparison;
}
return 0;
}
private int compareFields(Comparable field1, Comparable field2) {
if (field1 == null && field2 == null) {
return 0;
} else if (field1 == null && field2 != null) {
return -1;
} else if (field1 != null && field2 == null) {
return 1;
}
return field1.compareTo(field2);
}
#Override
public boolean equals(Object o) {
return this.compareTo(o) == 0;
}
}
UPDATE:
Found that using SortedSet as interface for TreeSet in combination with Hibernate the methods remove() and contains() does not work properly.
"SortedSet mailingAddresses = new TreeSet<>();"
Changed the definition to "Set mailingAddresses = new TreeSet<>();" and the methods remove() and contains() works fine; Also the sorting that is using compareTo() is working also for other fields than id.
Probably there is a bug in combination of TreeSet, SortedSet and Hibernate. If someone found an explanation for this "bug" please let me know.
Here is a working version:
#Entity
public class MailingAddress implements Identifiable, Comparable, Serializable {
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
private Integer age;
#Override
public int compareTo(Object o) {
if (o == null) {
return 1;
}
if (!(o instanceof MailingAddress)) {
throw new ClassCastException("Cannot compare MailingAddress with " + o.getClass());
}
MailingAddress o1 = (MailingAddress) o;
int comparison = compareFields(this.age, o1.age);
if (comparison != 0) {
return comparison;
}
return 0;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MailingAddress that = (MailingAddress) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return age != null ? age.equals(that.age) : that.age == null;
}
#Override
public int hashCode() {
return 31;
}
private int compareFields(Comparable field1, Comparable field2) {
if (field1 == null && field2 == null) {
return 0;
} else if (field1 == null && field2 != null) {
return -1;
} else if (field1 != null && field2 == null) {
return 1;
}
return field1.compareTo(field2);
}
}
AND
#Entity
public class Campaign implements Identifiable, Serializable {
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#OneToMany(mappedBy = "campaign", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#OrderBy("age ASC")
private Set<MailingAddress> mailingAddresses = new TreeSet<>();
...
}
The problem here is that you override equals without overriding hashCode.
Also, the reference check does not work for the merge entity state transition.
Since you don't have a natural business key in MailingAddress, you need to use the entity identifier like this:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MailingAddress)) return false;
MailingAddress ma = (MailingAddress) o;
return getId() != null && Objects.equals(getId(), ma.getId());
}
#Override
public int hashCode() {
return getClass().hashCode();
}
The getClass().hashCode() returns a constant value for allinstances, therefore allowing an entity that has a null id to be found in a HashSet even after the id is changed after calling persist on the transient entity.
But, that's not all.
Why do you use a TreeSet with #OrderBy("age ASC"). The order is given at query-time, and then you override that in Java. Since you use #OrderBy, it makes more sense to use a List since the sorting is done when executing the SELECT statement.

Hibernate Criteria, group/select distinct children of a parent

I have a model Parent, which has a list of Children (List
class Parent {
#OneToMany(targetEntity = Child.class, cascade = CascadeType.ALL, mappedBy = "parent")
#JsonManagedReference
private List<Child> tags = new ArrayList<>();
#Column(name = "name")
public String name;
}
class Child {
#Column(name = "name")
public String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id", nullable = true)
#JsonBackReference
private Parent parent;
}
I select a list of parents (List < Parent> ) with children in EAGER mode.
Now Children can have the same name, but I do not want children with the same name to be more than once in the list.
Any suggestions how have children with the same name only once in the collection?
Here is the sample code using set to remove repeated values. If firstName is present once second entry is ignored. You can modify if according to your needs.
However while this is the answer to the question you have asked please note there is a code smell here . They fact you are having to do this in code while database allows for it is questionable and almost guaranteed a design flaw.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Test
{
private String firstName;
private String lastName;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((firstName == null) ? 0 : firstName.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
return true;
}
public Test(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
public static void main(String[] args)
{
List<Test> aList = new ArrayList<Test>();
Test test1 = new Test("Tom","Hardy");
Test test2 = new Test("Tom","Cruise");
Test test3 = new Test("Any","Body");
aList.add(test1);
aList.add(test2);
aList.add(test3);
System.out.println("List values:");
for (Test test : aList)
{
System.out.println(test.firstName + "-"+ test.lastName);
}
Set<Test> alphaSet = new HashSet<Test>(aList);
System.out.println("Set values:");
for (Test test : alphaSet)
{
System.out.println(test.firstName + "-"+ test.lastName);
}
}
}

Column does not exist - Hibernate ManyToMany association class

I'm facing the following problem. Imagine this data model:
As you can see project_function entity is association many to many entity.
Here are my entity classes.
PeronalCard:
#Entity
#Table(name = "personal_card")
#XmlRootElement
public class PersonalCard implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_person")
private Integer idPerson;
/* SOME OTHER ATTRIBUTES */
#OneToMany(cascade = CascadeType.ALL, mappedBy = "projectFunctionPK.personalCard")
private Set<ProjectFunction> projectFunctionSet;
public PersonalCard() {
}
public Integer getIdPerson() {
return idPerson;
}
public void setIdPerson(Integer idPerson) {
this.idPerson = idPerson;
}
#XmlTransient
public Set<ProjectFunction> getProjectFunctionSet() {
return projectFunctionSet;
}
public void setProjectFunctionSet(Set<ProjectFunction> projectFunctionSet) {
this.projectFunctionSet = projectFunctionSet;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idPerson != null ? idPerson.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof PersonalCard)) {
return false;
}
PersonalCard other = (PersonalCard) object;
if ((this.idPerson == null && other.idPerson != null) || (this.idPerson != null && !this.idPerson.equals(other.idPerson))) {
return false;
}
return true;
}
}
Project:
#Entity
#Table(name = "project")
#XmlRootElement
public class Project implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_project")
private Integer idProject;
/* OTHER ATTRIBUTES*/
#OneToMany(cascade = CascadeType.ALL, mappedBy = "projectFunctionPK.project")
private Set<ProjectFunction> projectFunctionSet;
public Project() {
}
public Integer getIdProject() {
return idProject;
}
public void setIdProject(Integer idProject) {
this.idProject = idProject;
}
#XmlTransient
public Set<ProjectFunction> getProjectFunctionSet() {
return projectFunctionSet;
}
public void setProjectFunctionSet(Set<ProjectFunction> projectFunctionSet) {
this.projectFunctionSet = projectFunctionSet;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idProject != null ? idProject.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Project)) {
return false;
}
Project other = (Project) object;
if ((this.idProject == null && other.idProject != null) || (this.idProject != null && !this.idProject.equals(other.idProject))) {
return false;
}
return true;
}
}
ProjectFunction:
#Entity
#Table(name = "project_function")
#XmlRootElement
#AssociationOverrides({
#AssociationOverride(name = "projectFunctionPK.project",
joinColumns = #JoinColumn(name = "id_project", referencedColumnName = "id_project")),
#AssociationOverride(name = "projectFunctionPK.personalCard",
joinColumns = #JoinColumn(name = "id_person", referencedColumnName = "id_person")) })
public class ProjectFunction implements Serializable {
private static final long serialVersionUID = 1L;
protected ProjectFunctionPK projectFunctionPK;
private Date fromd;
private Date tod;
public ProjectFunction() {
this.projectFunctionPK = new ProjectFunctionPK();
}
#EmbeddedId
public ProjectFunctionPK getProjectFunctionPK() {
return projectFunctionPK;
}
public void setProjectFunctionPK(ProjectFunctionPK projectFunctionPK) {
this.projectFunctionPK = projectFunctionPK;
}
#Column(name = "fromd")
#Temporal(TemporalType.DATE)
public Date getFromd() {
return fromd;
}
public void setFromd(Date fromd) {
this.fromd = fromd;
}
#Column(name = "tod")
#Temporal(TemporalType.DATE)
public Date getTod() {
return tod;
}
public void setTod(Date tod) {
this.tod = tod;
}
#Transient
public Project getProject() {
return projectFunctionPK.getProject();
}
public void setProject(Project project) {
this.projectFunctionPK.setProject(project);
}
#Transient
public PersonalCard getPersonalCard() {
return this.projectFunctionPK.getPersonalCard();
}
public void setPersonalCard(PersonalCard personalCard) {
//this.personalCard = personalCard;
this.projectFunctionPK.setPersonalCard(personalCard);
}
#Override
public int hashCode() {
int hash = 0;
hash += (projectFunctionPK != null ? projectFunctionPK.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ProjectFunction)) {
return false;
}
ProjectFunction other = (ProjectFunction) object;
if ((this.projectFunctionPK == null && other.projectFunctionPK != null) || (this.projectFunctionPK != null && !this.projectFunctionPK.equals(other.projectFunctionPK))) {
return false;
}
return true;
}
}
And finally my embedded Primary Key ProjectFunctionPK:
#Embeddable
public class ProjectFunctionPK implements Serializable {
#ManyToOne
private Project project;
#ManyToOne
private PersonalCard personalCard;
public ProjectFunctionPK() {
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public PersonalCard getPersonalCard() {
return personalCard;
}
public void setPersonalCard(PersonalCard personalCard) {
this.personalCard = personalCard;
}
#Override
public int hashCode() {
int hash = 3;
hash = 41 * hash + Objects.hashCode(this.project);
hash = 41 * hash + Objects.hashCode(this.personalCard);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ProjectFunctionPK other = (ProjectFunctionPK) obj;
if (!Objects.equals(this.project, other.project)) {
return false;
}
if (!Objects.equals(this.personalCard, other.personalCard)) {
return false;
}
return true;
}
}
First I save the Project. It works fine. Then i want to connect it using project_function - so I create project_function set them existing project and personal_card and after trying to persist I get following error:
Caused by: org.postgresql.util.PSQLException: ERROR: column projectfun0_.personalcard does not exist
Position: 8
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:304)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:82)
... 119 more
So apparently Hibernate does not know projectfun0_.personalcard . But I dont know why. Do you see any error in the entity classes? Or could the error possibly be somewhere else ?
Thank you very much for all your answers :)
EmbeddedId documentation
Relationship mappings defined within an embedded id class are not supported.
So, ProjectFunctionPK should contain only basic mappings, and entity mappings should be done in the entity itself. Here are some related posts
https://stackoverflow.com/a/9760808/4074715
https://stackoverflow.com/a/4692144/4074715

many to one relationship between composite keys

I am building a spring mvc application with hibernate, and JPA that needs to model a few underlying MYSQL data tables that each have composite keys with the same two data types, so each table has its own composite key class, even though all the composite keys are based on the same two data types with exact same property names. I am getting a hibernate mapping error when I try to compile the app, and I am wondering if this might be because hibernate might not be able to equate the different primary key classes. Can someone show me how to fix this so that my app will compile?
Here is the part of my Description class that establishes the ManyToOne relationship between Description and Concept classes based on their corresponding composite primary key classes:
#ManyToOne
#JoinColumn(name="descriptionPK", referencedColumnName = "conceptPK")
private Concept concept;
Here is the error that I am getting:
Caused by: org.hibernate.MappingException:
Unable to find column with logical name:
conceptPK in org.hibernate.mapping.Table(sct2_concept) and its related supertables and secondary tables
The code for ConceptPK is:
#Embeddable
class ConceptPK implements Serializable {
#Column(name="id", nullable=false)
protected BigInteger id;
#Column(name="effectiveTime", nullable=false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime effectiveTime;
public ConceptPK() {}
public ConceptPK(BigInteger bint, DateTime dt) {
this.id = bint;
this.effectiveTime = dt;
}
/** getters and setters **/
public DateTime getEffectiveTime(){return effectiveTime;}
public void setEffectiveTime(DateTime ad){effectiveTime=ad;}
public void setId(BigInteger id) {this.id = id;}
public BigInteger getId() {return id;}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final ConceptPK other = (ConceptPK) obj;
if (effectiveTime == null) {
if (other.effectiveTime != null) return false;
} else if (!effectiveTime.equals(other.effectiveTime)) return false;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + ((effectiveTime == null) ? 0 : effectiveTime.hashCode());
hash = 53 * hash + ((id == null) ? 0 : id.hashCode());
return hash;
}
}
The code for DescriptionPK is:
#Embeddable
class DescriptionPK implements Serializable {
#Column(name="id", nullable=false)
protected BigInteger id;
#Column(name="effectiveTime", nullable=false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime effectiveTime;
public DescriptionPK() {}
public DescriptionPK(BigInteger bint, DateTime dt) {
this.id = bint;
this.effectiveTime = dt;
}
/** getters and setters **/
public DateTime getEffectiveTime(){return effectiveTime;}
public void setEffectiveTime(DateTime ad){effectiveTime=ad;}
public void setId(BigInteger id) {this.id = id;}
public BigInteger getId() {return id;}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final DescriptionPK other = (DescriptionPK) obj;
if (effectiveTime == null) {
if (other.effectiveTime != null) return false;
} else if (!effectiveTime.equals(other.effectiveTime)) return false;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + ((effectiveTime == null) ? 0 : effectiveTime.hashCode());
hash = 53 * hash + ((id == null) ? 0 : id.hashCode());
return hash;
}
}
You need to change #ManyToOne annotation to use multiple columns as shown below, and also you dont need to create duplicate two embeddable classes ConceptPK and DescriptionPK if all properties are same, just create one EmbeddablePK and use in both entities.
#OneToMany(mappedBy = "concept", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<Description> descriptions = new LinkedList<Description>();
And Description class:
#ManyToOne
#JoinColumns({ #JoinColumn(name = "A_COLUMN", referencedColumnName = "A_COLUMN", insertable = false, updatable = false),
#JoinColumn(name = "B_COLUMN", referencedColumnName = "B_COLUMN", insertable = false, updatable = false),
})
public Concept concept;

Save object with Hibernate annotations?

I just wanna ask know how its possible to create object after creating your database with Hibernate annotations?
When i run the code below, it creates the database with the objects, but when i run the second time it just creates exactly the same, and none new objects are added? How come? How do i create objects using annotations with the method .save, after creating the database with annotations? Or is it not possible to do so with annotations?
Thanks in advance.
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Adress adress = new Adress("Streetname", "postcode");
Person person1 = new Person("Peter Hanks", adress);
Person person2 = new Person("Sophie Hanks", adress);
session.save(person1);
session.save(person2);
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
Heres the code person.class
#Entity
#Table(name="person")
public class Person implements Serializable {
private long id;
private String navn;
private Adresse adresse;
public Person() {
}
public Person(String navn, Adresse adresse) {
this.navn = navn;
this.adresse = adresse;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name= "adresse_id", nullable = false)
public Adresse getAdresse() {
return adresse;
}
public void setAdresse(Adresse adresse) {
this.adresse = adresse;
}
#Id
#GeneratedValue
#Column(name= "id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "navn", nullable= false, length= 100)
public String getNavn() {
return navn;
}
public void setNavn(String navn) {
this.navn = navn;
}
#Override
public int hashCode() {
int hash = 3;
hash = 29 * hash + (this.navn != null ? this.navn.hashCode() : 0);
hash = 29 * hash + (this.adresse != null ? this.adresse.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.navn == null) ? (other.navn != null) : !this.navn.equals(other.navn)) {
return false;
}
if (this.adresse != other.adresse && (this.adresse == null || !this.adresse.equals(other.adresse))) {
return false;
}
return true;
}
You might need to show us how you've written and annotated your Person and Adress (sic) objects.
If you've written "correct" equals() and hashcode() implementations (i.e. that don't look at the #Id of the object) then your save() calls will do nothing the second time around because the objects you've asked to save already exist in the database.
just changed the settings for hibernate.hbm2ddl.auto from create to create-update, and now theres no problem...

Categories