Cannot update entity with spring Crude Repository - java

I am absolute beginner in Spring and need some help. Code below is service layer and is intended to update organisation entity in CrudeRepository, but it only saves new organisation. Just can't imaginate what is wrong.
if (repository.exists(organisation.getId())) {
repository.save(organisation);
}
Organisation.java
#Entity
#Table(name = "organisations")
public class Organisation implements Serializable {
#Id
#GeneratedValue
private long id;
#Version
private Integer version;
#NotNull
#Size(min=3, max=100)
#Basic(optional = false)
#Column(length = 100)
private String name;
#Column(name = "full_name")
private String fullName;
private long inn;
private long kpp;
private String address;
private long phone;
#AssertTrue
#Column(name = "is_active")
private boolean isActive;

Probably your organization object is not managed by spring (it's a raw object, not a managed entity), try finding the object first and then updating the java object and finally save.
Long id = ...
if (repository.exists(id)) {
Organization organization = repository.getOne(id);
// ...
// Update objects field e.g. organization.setName("New Name");
// ...
repository.save(organisation);
}
Note you're using the #Version annotation, when the current version is null spring considers the entity as new. So this field shouldn't be null to update instead insert.

Related

OneToOne and OneToMany not storing Parent Id (IdClass)

I am currently working on a project with following data structure:
public class PinaColadaId implements Serializable {
private UUID id;
#Temporal(TemporalType.TIMESTAMP)
private Date time;
// Constructor + Getters and Setters
}
#Entity
#Table(name = "pina_coladas")
#IdClass(PinaColadaId.class)
public class PinaColadaEntity {
#Column(columnDefinition = "char(255)")
#Type(type="org.hibernate.type.UUIDCharType")
private #Id UUID id;
private #Id #Temporal(TemporalType.TIMESTAMP) Date time;
#OneToOne(mappedBy = "entityID", cascade=CascadeType.ALL)
private PineappleWrapper pineapple;
#OneToMany(mappedBy = "entityID", cascade=CascadeType.ALL)
private List<CoconutWrapper> coconuts;
// Constructor + Getters and Setters
}
#Entity
public class PineappleWrapper {
private #Id #GeneratedValue long id;
private String manufacturer;
private String origin;
#OneToOne
private PinaColadaEntity entityID;
// Constructor + Getters and Setters
}
#Entity
public class CoconutWrapper {
private #Id #GeneratedValue long id;
private int shipmentNumber;
private int juice;
#ManyToOne
private PinaColadaEntity entityID;
// Constructor + Getters and Setters
}
The issue is that Spring Boot together with Hibernate and JPA correctly generate all the tables in my database, however when I attempt to store PineappleWrapper or CoconutWrapper, it stores all the values of PineappleWrapper and/or CoconutWrapper except for the id and time of the parent. The columns are generated yet they store the value "null".
Any and all help is much appreciated, -AwesomeDude091
Edit: I am aware of the JoinColumn annotation and it proposed implementation in my Wrapper classes, but I do not know how to use them with my two ID variables (id and time)

How to create a 1:n relationship with hibernate?

I am using hibernate to represent a database with the three major Entities User, Project and Comment. User and Project inherit from Base class. The Project also holds an unlimited amount of comments.
In the POJO i tried to represent the collection of comments associated by a project by with a List<Comment>.
My major problem is, when i i go and take a project which holds a number of comment references within the list java will throw an IllegalArgumentException saying, that it cant access the id field of comment, as it only gets an ArrayList.
Caused by: java.lang.IllegalArgumentException: Can not set int field com.project.objects.Comment.id to java.util.ArrayList
My classes are as followed - without Constructor/Setter/Getter as these are plain simple:
#MappedSuperclass
public abstract class Base {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String name;
#Column
private String longDesc;
#Column
private String briefDesc;
#Column
#ElementCollection(targetClass=String.class)
private List<String> goals;
#Column
private String picture;
#Column
private int cType;
#Entity(name = "Project")
#Table(name = "project")
public class Project extends Base {
#Column
private String start;
#Column
private String end;
#Column
private String manager;
#ElementCollection(targetClass=Comment.class)
#ManyToOne(targetEntity = Comment.class, fetch = FetchType.EAGER)
#JoinColumn(name = "comment_id")
private List<Comment> comments;
#Entity(name = "Comment")
#Table(name = "comment")
public class Comment {
#Id
#Column(name="comment_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String comment;
#Column
private int rating;
#Column
private int pcuser;
#Column
private int cType;
Your 1:N association is wrong, as it is actually a N:1 right now. The correct would be:
Entity(name = "Project")
#Table(name = "project")
public class Project extends Base {
#Column
private String start;
#Column
private String end;
#Column
private String manager;
#OneToMany(mappedBy = "project", fetch = FetchType.EAGER)
private List<Comment> comments;
And in your Comment class:
#Entity(name = "Comment")
#Table(name = "comment")
public class Comment {
#Id
#Column(name="comment_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String comment;
#Column
private int rating;
#Column
private int pcuser;
#Column
private int cType;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_project", nullable = false)
private Project project;
// THIS is the required and obrigatory mapping that you forgot.
// It's the foreing key itself
Disclaimer
I've never actually used Hibernate with inheritance before (usually, it's desnecessarily complex and also inefficient for a relational database) but check `https://www.baeldung.com/hibernate-inheritance` and `https://marcin-chwedczuk.github.io/mapping-inheritance-in-hibernate` for more information.
You're using a #ManyToOne annotation for comments but it should be #OneToMany.
In order to use #OneToMany you would have to have a column called something like project_id in the comment table, which you would reference from the #OneToMany field. Do you have that?
If not, how are you linking comments to projects in your database?
By the way, it's really easy to create poorly-performing systems with Hibernate, because it tends to obscure the cost of hitting the database. You've said that there can be any number of comments associated with a project. Do you really want to load them all every time the code loads a project? Let's say you just want a list of projects, for example to populate a selection list. Simply loading that list will also load every comment in the system, even though you don't actually need them.
Comment is an entity and should not be used with the #ElementCollection inside the Project entity.
Your relationship is a project to many comments. #OneToMany

Spring data jpa find by multiple fields in embedded key

I need to find an object using two fields of an embedded key
Here is the embedded key:
public class OrderItemId implements Serializable {
private static final long serialVersionUID = 1163347452811191867L;
#Column(name = "order_code", length = 25)
private String orderCode;
#Column(name = "barcode", length = 25)
private String barcode;
// ....
}
Here is the class of the object I want to query:
#Entity
#Table(name = "order_item")
public class OrderItem {
#EmbeddedId
#NotNull
private OrderItemId id;
#Column(name = "quantity")
private Integer quantity;
#Column(name = "price")
private Double price;
// ...
}
As in this StackOverflow Answer
To query by embedded key orderCode, I can write something like this
public List<OrderItem> findById_OrderCode(String orderCode);
and it works!
But I don't know how to query by both orderCode and barcode. I have tried some forms of and but no use.
Never mind, I have figured out the query, it is
public OrderItem findById_OrderCodeAndId_Barcode(String orderCode, String barcode);

How does the OneToMany annotation with fetch work?

Hibernate newbie here.
So I have a User object with many Opportunity objects:
#Entity
public class User implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
private String firstName;
private String lastName;
private String email;
#OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL, mappedBy="user")
private List<Opportunity> opportunities = new ArrayList();
#Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
And I have an Opportunity object with a ManyToOne relation with a User:
#Entity
public class Opportunity implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long opportunityId;
#ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="userId", nullable=false)
private User user;
private String listingUrl;
private String position;
private String organization;
private String location;
#Column(columnDefinition="text")
private String notes;
#Enumerated(EnumType.STRING)
private Action action;
#Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
#Temporal(TemporalType.DATE)
private Date dueDate;
All get/set methods are emitted here just to save space.
What I assumed would happen when I used the getOpportunities() method of the User class, was that it would return all the Opportunity objects in the database. I figured that the annotations would pull them automatically for me. However, it did not.
So my question is, do the annotations help retrieve data from the database? How? Or are they just used for creating the database? If I want to get all the opportunities, do I have to write a custom transaction/query?

JPA - manytoone cascading

I've got two entities
ServiceDownload.java
#Entity
public class ServiceDownload implements Serializable {
private static final long serialVersionUID = -5336424090042137820L;
#Id
#GeneratedValue
private Long id;
#Length(max = 255)
private String description;
private byte[] download;
private String fileName;
#ManyToOne
private Service service;
Service.java
#Entity
public class Service implements Serializable {
private static final long serialVersionUID = 4520872456865907866L;
#EmbeddedId
private ServiceId id;
#Length(max = 255)
private String servicename;
#Column(columnDefinition = "text")
private String highlightsText;
#Column(columnDefinition = "text")
private String detailsText;
#Column(columnDefinition = "text")
private String productText;
#Column(columnDefinition = "text")
private String dataText;
#ManyToMany(mappedBy = "services")
private Set<Machine> machines;
#OneToMany(targetEntity = ServiceDownload.class)
private List<ServiceDownload> serviceDownloads;
#OneToOne
private ServicePicture servicePicture;
When I create a new ServiceDownload Object and try to persists this I recieve a duplicate key exception. It seems that jpa tries to insert a new service object into the service table. How can I disable this behaviour?
You are using #GeneratedValue annotation for your #Id. According to JPA documentation, you should supply unique identifiers
By default, the application is responsible for supplying and setting entity identifiers (see #Id)
Try using a #SequenceGenerator and a sequence in your database to generate unique identifiers

Categories