I setup the "unique" value for the date column
anyways, anytime I post a new object with the same date it lets it happen.
I know I could design the unique constraint directly in the database
but isnt it possible to do it here?
It is a REST application, I am Posting a JSON object like this:
'{
"date":"2022-10-17"
}'
Model:
#Entity
#Table(name = "daylife")
public class DayLife {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false, unique = true)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate date;
Ok, as I added the UNIQUE parameter in the class
AFTER the table as already created, I deleted the table
and Spring created it again and now it has the Constraint.
Related
I have two spring entities, job and employer, which have a bidirectional association.
Job Entity
#Entity
#Table(name = "job")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Job {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "job_id", nullable = false)
private Integer id;
#Column(name = "title", nullable = false)
private String title;
#ManyToOne(optional = false)
#JoinColumn(name = "employer_employer_id", nullable = false)
#JsonBackReference
private Employer employer;
}
Employer Entity
#Entity
#Table(name = "employer")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Employer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "employer_id", nullable = false)
private Integer employerId;
#Column(name = "name", nullable = false)
private String name;
//Mapped by indicates the inverse side of the relationship.
#OneToMany(mappedBy = "employer", orphanRemoval = true)
#JsonManagedReference
private List<Job> jobs = new ArrayList<>();
}
I also have two simple CRUD repositories
Let's say that I have an existing employer object saved in the database. In my jobs service, I want to have a method that creates a new job. My question is, what is the correct Spring boot way to save a new job entry in the database where the employee id foreign key relates back to that existing job in the database.
Here is my first attempt, and it works, however it doesn't seem very efficient. Why should I have to retrieve the entire employer object from the database, when I really just want to specify the employer ID of the job I am trying to save? Is there a way I can avoid making this extra database call, and when we are saving the job to the database, just easily specify an existing employer ID on that new job we are saving to the database? Or is it Spring best practice to have to save the entire employee object here, even if it already exists?
Employer e = employerRepository.findById(0).orElseThrow(IllegalArgumentException::new);
job1.setEmployer(e);
jobRepository.save(job1);
Best way is use getOne so you don't even have to fetch the empoyer
Employer e = employerRepository.getOne(id);
job1.setEmployer(e);
jobRepository.save(job1);
If employer does t exist an exception will be thrown when you save job.
getOne is deprecated in later versions of jpa so use this instead
JpaRepository#getReferenceById(ID)
Good/progressive question:
Why should I have to retrieve the entire employer object from the database, when I really just want to specify the employer ID of the job I am trying to save?
We don't have to! We can:
Employer empler =
entityManager.getReference(Employer.class, 0L);
// handle exception...
Resp. with spring-data:
JPARepository.getReferenceById(...);
"must read" article
jpa-javadoc
spring-data-javadoc
Regarding "how to do it best" (and in which queries it results), i can additionally very recommend:
https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/
(Where Employer is analogous to Post and Job analogous to PostComment;)
I have generated master tables using liquibase. I have created the corresponding models in spring boot now I want to maintain a relation ship between those models.
I have one table called Vehicle_Type, it is already pre-populated using liquibase.
#Data
#Entity
#Table(name="VEHCILE_TYPE")
public class VehicleType {
#Id
private int id;
#Column(name="DISPLAY_NAME")
private String displayName;
#Column(name="TYPE")
private String type;
#Column(name="CREATED_DATE")
private LocalDateTime createdDate;
#Column(name="UPDATED_DATE")
private LocalDateTime updateDate;
}
now what I want to achieve is, I have one child entity, I have refer the VehicleType instance inside that entity as depicted below
#Data
#Entity
#EqualsAndHashCode(callSuper = true)
#Table(name = "NON_MSIL_VEHICLE_LAYOUT")
public class NonMsilVehicleLayout extends BaseImagesAndLayout {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "NMV_SEQ")
#SequenceGenerator(sequenceName = "NON_MSIL_VEH_SEQUENCE", allocationSize = 1, name = "NMV_SEQ")
private int id;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "VEH_TYPE", referencedColumnName = "id")
private VehicleType vehicleType;
public interface VehType {
String getVehType();
}
}
The problem is when I tries to save entity NonMsilVehicleLayout, then it tries to first insert the data in VEHICLE_TYPE table also. which should not going to be happen.
I don't want that, I want JPA will pick the correct ID from VEHICLE_TYPE table and place it inside the corresponding table for NonMsilVehicleLayout, because the id of VEHICLE_TYPE table is act as foreign key in Non_Msil_Vehicle_Layout table.
log.info("Inside saveLayout::Start preparing entity to persist");
String resourceUri = null;
NonMsilVehicleLayout vehicleLayout = new NonMsilVehicleLayout();
VehicleType vehicleType=new VehicleType();
vehicleType.setType(modelCode);
vehicleLayout.setVehicleType(modelCode);
vehicleLayout.setFileName(FilenameUtils.removeExtension(FilenameUtils.getName(object.key())));
vehicleLayout.setS3BucketKey(object.key());
I know I missed something, but unable to figure it out.
You are creating a new VehicleType instance setting only the type field and set the vehicleType field of NonMsilVehicleLayout to that new instance. Since you specified CascadeType.ALL on NonMsilVehicleLayout#vehicleType, this means to Hibernate, that it has to persist the given VehicleType, because the instance has no primary key set.
I guess what you rather want is this code:
vehicleLayout.setVehicleType(
entitManager.createQuery("from VehicleType vt where vt.type = :type", VehicleType.class)
.setParameter("type", typeCode)
.getSingleResult()
);
This will load the VehicleType object by type and set that object on NonMsilVehicleLayout#vehicleType, which will then cause the foreign key column to be properly set to the primary key value.
Finally, after some workaround, I got the mistake, the column name attribute was incorrect, so I made it correct and remove the referencedColumn and Cascading.
Incorrect:
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "VEH_TYPE", referencedColumnName = "id")
private VehicleType vehicleType;
Correct:
#OneToOne
#JoinColumn(name = "VEHICLE_TYPE")
private VehicleType vehicleTypes;
also I have added the annotation #Column in the referende entity VehicleImage
public class VehicleType {
#Id
#Column(name = "ID") // added this one
private int id;
}
That bit workaround solved my problem, now I have achieved what I exactly looking for.
I hope you are very well.
Right now, I am working a project in JAVA which uses Spring Framework and JPA repositories.
Like it is normal, I am trying to get information from a table be means the following JPA method:
Optional<Car> = findByNameAndModelDtIsLessThanEqual(String name, Java.sql.Date modelDt);
Where entity Car has the following definition:
#Entity
#Table(name = "car")
public class Car{
#Id
#Column(name = "car_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer carId;
#Column(name = "name")
private String name;
#Column(name = "model_dt")
private Date modelDt;
//Getters and Setters
}
when I am debugging the code, the argument in the method are:
name: "VW"
modelDT: '2020-03-02'
However the JPA query is not working, because in the database the model_dt field appears with the "dd-MON-yy" format ("02-MAR-20") and the java.sql.Date has other format ("yyyy-mm-dd").
I have tried to replace java.sql.Date modelDt by String modelDt in the definition repository (with the intention to use SimpleDateFormat class), However, it has not worked of this way.
I would like to know if there is one way to compare Dates from JPA (I would like to avoid using JPQL).
Does someone know how can I solve this.
Regards.
I have an application that contains some JPA classes that are using LocalDate / LocalDateTime fields and these fields are being mapped into PostgreSQL columns as Bytea.
The greatest problem with this approach is that I can't do queries with SQL, for example, I can't query this: SELECT * FROM star_date BETWEEN '2020-01-01' AND '2020-01-02', because DateTime and date columns using the Bytea type.
Below a have an example of a class that shows my current problem scenery! This class is using JPA to generate the table in PostgreSQL, so it happens automatically. Look at created fiend into class and design of the table.
#Data
#Entity
#Table(name = "processes")
public class Process implements Serializable {
#Id
#GeneratedValue(generator = "ProcessSequenceGenerator")
private Long id;
private Long legacyId;
private String createdBy;
private LocalDateTime created;
}
The table design:
Has somebody ever had an issue like this one?
I'm using Spring Boot 1.4.7.RELEASE! So a fix my problem including into Column the property columnDefinition and a #Convert like below:
#Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP")
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime created;
Right now, I'm looking for a way to convert bytea that is into my current table in postgresql.
I am new in Spring Data, and I need to establish the impossibility of creating a new entity in DB if an entity already exists with the same field values.
Comparison condition: if "closeType" field and "id" agreement field of a new entity equal to database entity fields, I can't add this entity to DB. How do it?
My entity:
#Entity
#Table(name = "contract")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Contract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contractGenerator")
#SequenceGenerator(name = "contractGenerator", sequenceName = "contract_sequence")
private Long id;
#Column(name = "start_date")
private LocalDate startDate;
#Column(name = "end_date")
private LocalDate endDate;
#Column(name = "first_pay_date")
private LocalDate firstPayDate;
#Column(name = "next_pay_date")
private LocalDate nextPayDate;
//Here is thу first field for comparison
#Enumerated(EnumType.STRING)
#Column(name = "close_type")
private CloseType closeType;
#ManyToOne
#JsonIgnoreProperties("")
private Mentor mentor;
//Here is second ID agreement field for comparison
#ManyToOne
#JsonIgnoreProperties("")
private Agreement agreement;
...............
//getters and setters
I have to block possibility to create several active contracts("closeType") in one agreement ("id")
I have to block possibility to create several active
contracts("closeType") in one agreement ("id")
you could use UniqueConstraint How to introduce multi-column constraint with JPA annotations?
...
#Table(uniqueConstraints={
#UniqueConstraint(columnNames = {"close_type", "agreement"})
})
Contract implements Serializable {
...
}
Thanks, maybe you could hint me how to set constraint for "closeType"
if, for example, only closeType fields with Null value will be uniqe?
But other values of closeType wont be uniqe
How to annotate unique constraint with WHERE clause in JPA says:
creating partial indexes (CREATE INDEX ... ON ... WHERE) using JPA
aren't specified by JPA. You cannot use a unique constraint for this
purpose because unique partial indexes are not unique constraints.
Some JPA providers offer extension annotations specific to that JPA
provider that add features for running native DDL scripts, defining
indexes with annoations, etc. Since you haven't mentioned which JPA
provider you are using I can't tell you more. Here's the documentation
for EclipseLink index DDL;
I suggest you to have a look at the
How to annotate unique constraint with WHERE clause in JPA