JPA find by foreign key - java

I have the following class:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "Municipios")
public class Municipio {
#Id
private String nombreMunicipio;
#ManyToOne
#JoinColumn(name = "nombreProvincia", nullable = false)
private Provincia nombreProvincia;
}
how would I go about getting all the Municipios given the string ID of the province? what would the controller and repository look like? I've been trying for hours and can't find the answer
Edit: decided to post my repository and controller
public interface MunicipioRepo extends JpaRepository<Municipio, Integer> {
boolean existsByNombreMunicipio(String nombreMunicipio);
Municipio findByNombreMunicipio(String nombreMunicipio);
List<Municipio> findAllByNombreProvincia(final Provincia provincia);
}
#GetMapping("/municipiosenprovincia")
public List<Municipio> getMunicipiosEnProvincia(#RequestParam String nombreProvincia){
System.out.printf(nombreProvincia);
Optional<Provincia> miProv = provinciaRepo.findById(nombreProvincia);
return municipioRepo.findAllByNombreProvincia(miProv.get());
}

Assuming that primary key of Provincia is id:
public interface MunicipioRepo extends JpaRepository<Municipio, Integer> {
...
List<Municipio> findAllByNombreProvinciaId(final String provinciaId);
}
And just pass provinciaId to this method:
// getMunicipiosEnProvincia method in controller
...
return municipioRepo.findAllByNombreProvinciaId(nombreProvincia); // here nombreProvincia is the id of Provincia

Related

Why am I receiving a "Request method 'POST' not supported" ? I get error code 405 on postman

Postman error
Controller:
#RestController
#RequestMapping("/student_enrollment/class_subject")
public class ClassController {
private ClassService classService;
public ClassController(ClassService classService) {
super();
this.classService = classService;
}
#PostMapping()
public ResponseEntity<Classes> saveClass(#RequestBody Classes classes) {
return new ResponseEntity<Classes>(classService.saveClass(classes),
HttpStatus.CREATED);
}
#GetMapping
public List<Classes> getAllClasses() {
return classService.getAllClasses();
}
model:
#Data
#Entity
#Table(name = "class_subject")
public class ClassSubject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int subject_id;
#Column(value = "prerequisite")
private String prerequisite;
#Column(value = "max_capacity")
private int max_capacity;
}
service impl:
#Service
public class ClassServiceImpl implements ClassService{
#Override
public ClassSubject updateClassSubject(ClassSubject classSubject, int classSubjectId) {
ClassSubject existingClassSubject = classSubjectRepository.findById(classSubjectId).orElseThrow(() -> new ResourceNotFoundException("ClassSubject", "classSubjectId", classSubjectId));
existingClassSubject.setSubject_id(classSubject.getSubject_id());
existingClassSubject.setPrerequisite(classSubject.getPrerequisite());
existingClassSubject.setMax_capacity(classSubject.getMax_capacity());
classSubjectRepository.save(existingClassSubject);
return existingClassSubject;
}
Service:
public interface ClassService {
Classes saveClass(Classes classes);
List<Classes> getAllClasses();
Classes getClassByID(int classId);
Classes updateClass(Classes classes, int classId);
void deleteClass(int classId);
}
SQL Queries:
CREATE TABLE class_subject(
subject_id INT NOT NULL,
prerequisite VARCHAR(30),
max_capacity INT NOT NULL,
PRIMARY KEY (subject_id)
);
Because in Postman you are using PUT method, not the POST method.
Let me guess you are expecting 'subject_id' to be auto-generate using database sequence. Then you are missing two annotations #GeneratedValue and #SequenceGenerator.
As 'subject_id' is not an optional field. That's why you getting the error "Field 'subject_id' doesn't have a default value".
To create a relationship between the 'subject_id' field and DB sequence use the following.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#SequenceGenerator(name="seq",sequenceName="sequence_in_db")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private int subject_id;
You can find more details on this topic what is the use of annotations #Id and #GeneratedValue(strategy = GenerationType.IDENTITY)? Why the generationtype is identity?

JPA Problem, Using Parent Entity's Primary Key for Child's Entity's Primary Key

I'm currently developing my project under Spring with JPA.
First off, here is my database schema for the background information
So, I'm undergoing difficulties when I try to use history_id of HISTORY as the primary key of TAG. It gives me ...Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class com.wrapsody.demo.HistoryTag] does not define an IdClass error.
So I added #IdClass(HistoryTag.HistoryTagAssignId.class) in my HistoryTag.java
#NoArgsConstructor(access = AccessLevel.PROTECTED) #Data #Entity
#IdClass(HistoryTag.HistoryTagAssignId.class)
public class HistoryTag implements Serializable {
#Id
#ManyToOne
private History history;
#Column
private String tagName;
#Builder
public HistoryTag(String tagName) {
this.tagName = tagName;
}
#NoArgsConstructor
public static class HistoryTagAssignId implements Serializable {
private History history;
public HistoryTagAssignId(History history) {
this.history = history;
}
}
}
For the reference, this is History.java
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#Data
#Entity
public class History {
#Id
#GeneratedValue
private Long historyId;
#Column
private String historyMaterName;
#Column
private String historyFreeSetName;
History(String historyMaterName, String historyFreeSetName) {
this.historyMaterName = historyMaterName;
this.historyFreeSetName = historyFreeSetName;
}
}
Any guidance towards solving this error msg is appreciated.
Thanks!
For tag table you dont need entity class. Its duable in History entity with:
#ElementCollection
#CollectionTable(
name="TAG",
joinColumns=#JoinColumn(name="HISTORY_ID")
)
#Column(name="TAG_NAME")
List<String> tags;
https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection#Basic_Collections

using embedded id type twice in an entity

In my spring-boot project, I have a custom type for ID field of my entity. I can use the type with the help of #Embeddable and #EmbeddedId.
But when I want to add another field with the same type into a single entity, I get a column mapping exception as follows:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity:
com.example.demo.CarEntity column: id (should be mapped with insert="false" update="false")
CarId class:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Embeddable
public class CarId implements Serializable {
private String id;
#Override
public String toString() {
return id;
}
}
CarEntity class:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
public class CarEntity {
#EmbeddedId
private CarId id;
private String name;
private CarId anotherId;
}
Repository class:
#Repository
public interface CarRepository extends JpaRepository<CarEntity, CarId> {
}
application class:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
CommandLineRunner runner(CarRepository repository) {
return args -> {
CarId carId = new CarId(UUID.randomUUID().toString());
String carName = "a car";
CarEntity carEntity = new CarEntity(carId, carName, carId);
repository.save(carEntity);
repository.findAll().forEach(carEntity1 -> {System.out.println(carEntity1.getId());});
};
}
}
How can I add multiple fields with the same type into the entry class?
The solution I found is to override the field name on anotherId as follows:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
public class CarEntity {
#EmbeddedId
private CarId id;
private String name;
#Embedded
#AttributeOverride(name="id", column = #Column(name = "anotherId"))
private CarId anotherId;
}

Custom bridge table in playframework ebean

I am unsuccessfuly trying to create bridge table that would resolve two #ManyToMany relations. However this table have to contain additional field. For example:
Course: -course_id - pk
Student: -student_id -pk
Bridge: -(course_id, student_id) - pk
-additional_field
My student class looks like this:
#Entity
public class Student extends Model {
#Id
#OneToMany
public List<Bridge> student_id;
}
Course class is basicaly the same.
Bridge table looks like this:
#Entity
public class Bridge extends Model{
#EmbeddedId
public compound_key student_course;
public String additional_field;
#Embeddable
public class compound_key{
#ManyToOne
public Student student_id;
#ManyToOne
public Student course_id;
}
}
Thank you for help.
I have found the following solution. This is a solution without a composite key in Bridge. I added normal #Id field in Bridge class and relations to Student and Course are normal relations.
This solution contains an additional 'id' field in the 'bridge' table in the database.
Here is the code:
Student.java:
#Entity
public class Student extends Model {
#Id
public Integer id;
#OneToMany(mappedBy="student")
public List<Bridge> bridges;
public static Finder<Integer,Student> find = new Finder<Integer,Student>(
Integer.class, Student.class
);
}
Course.java:
#Entity
public class Course extends Model {
#Id
public Integer id;
#OneToMany(mappedBy="course")
public List<Bridge> bridges;
public static Finder<Integer,Course> find = new Finder<Integer,Course>(
Integer.class, Course.class
);
}
Bridge.java:
#Entity
public class Bridge extends Model {
#Id
public Integer id;
#ManyToOne public Student student;
#ManyToOne public Course course;
public String additional_field;
public static Finder<Integer,Bridge> find = new Finder<Integer,Bridge>(
Integer.class, Bridge.class
);
}
EDIT
After many attempts I have found solution with composite key in Bridge class. Classes Student and Course are the same as in previous solution.
Bridge.java changed to following:
#Entity
public class Bridge extends Model {
Bridge() {
bridgeId = new BridgeId();
}
#EmbeddedId
protected BridgeId bridgeId;
#ManyToOne
#JoinColumn(name = "student_id", insertable = false, updatable = false)
private Student student;
#ManyToOne
#JoinColumn(name="course_id", insertable = false, updatable = false)
private Course course;
public String additional_field;
public Student getStudent() {
return student;
}
public void setStudent(Student aStudent) {
student=aStudent;
bridgeId.student_id = aStudent.id;
}
public Course getCourse() {
return course;
}
public void setCourse(Course aCourse){
course=aCourse;
bridgeId.course_id = aCourse.id;
}
}
And there is additional BridgeId.java:
#Embeddable
public class BridgeId implements Serializable
{
public Integer student_id;
public Integer course_id;
public int hashCode() {
return student_id + course_id;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
BridgeId b = (BridgeId)obj;
if(b==null)
return false;
if (b.student_id == student_id && b.course_id == course_id) {
return true;
}
return false;
}
}
What is more important in this code is:
Fields of embedded id are mapped to the same columns as ManyToOne relations.
Value to 'student_id' and 'course_id' columns are inserted from embedded id and not from relations. This is because relations have attributes 'insertable' and 'updatable' set to false.
I had to add getters and setters to 'student' and 'course' fields. In setters I am updating fields of embedded key.
Above solution has several workarounds. But I wasn't ableto find easier and cleaner one.

How do I setup annotations for JOINED inheritance with composite PK in hibernate?

I am new to hibernate and having a tough time trying to wrap my head around setting up Joined inheritance with composite Primary Key. With my current setup, I get a:
JDBCException: could not insert: LandHolidayPackage
I am essentially looking for two things:
Are the inheritance annotations in place ?
Is the composite PK setup properly ?
DB Design:
Reference
Here are my classes and the annotations involved:
#Entity
#Table(name = "HOLIDAYPACKAGE")
public final class HolidayPackage {
private Integer idPackage;
private String name;
private Set<HolidayPackageVariant> holidayPackageVariants = new HashSet<HolidayPackageVariant>(0);
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDHOLIDAYPACKAGE", nullable = false)
public Integer getIdPackage() {
return idPackage;
}
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "holidayPackage")
public Set<HolidayPackageVariant> getHolidayPackageVariants() {
return holidayPackageVariants;
}
// ommitted other part of the code
}
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name="HOLIDAYPACKAGEVARIANT")
public abstract class HolidayPackageVariant {
private Integer idHolidayPackageVariant;
private HolidayPackage holidayPackage;
private String typeHolidayPackage;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="IDHOLIDAYPACKAGEVARIANT", nullable=false)
public Integer getIdHolidayPackageVariant() {
return idHolidayPackageVariant;
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDHOLIDAYPACKAGE", nullable=false)
public HolidayPackage getHolidayPackage() {
return holidayPackage;
}
#Column(name="TYPEHOLIDAYPACKAGE", nullable=true)
public String getTypeHolidayPackage() {
return typeHolidayPackage;
}
// ommitted setters, equals hashCode
}
#Entity
#Table(name="LANDHOLIDAYPACKAGEVARIANT")
public final class LandHolidayPackageVariant extends HolidayPackageVariant{
private static final String LAND = "LAND";
protected LandHolidayPackageVariant() {}
public LandHolidayPackageVariant(HolidayPackage holidayPackage) {
super(holidayPackage, LAND);
}
}
#Entity
#Table(name="FLIGHTHOLIDAYPACKAGEVARIANT")
public final class FlightHolidayPackageVariant extends HolidayPackageVariant{
private static final String FLIGHT = "FLIGHT";
private Destination originCity;
protected FlightHolidayPackageVariant(){}
public FlightHolidayPackageVariant(HolidayPackage holidayPackage,
Destination originCity) {
super(holidayPackage, FLIGHT);
setOriginCity(originCity);
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDDESTINATION", nullable=false)
public Destination getOriginCity() {
return originCity;
}
// ommited other setters etc functions
}
You annotated the properties in stead of the fields. JPA by default tries to access the fields. If you want JPA to use the fields you have to annotate the class with #AccessType(AccessType.Field).

Categories

Resources