Column 'id' not found when request is raised with existed friends in list for third table of many-to-many relation - many-to-many

I have created the Friends table which have self join ManyToMany relation. Friends entity have List of Friends which result as third table for representing the ManyToMany relation.
public class Friends {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
#ManyToMany
#JoinTable(
name = "friends_list",
joinColumns = #JoinColumn(name = "friends_from"),
inverseJoinColumns = #JoinColumn(name = "friends_to"))
#Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.PERSIST})
private List<Friends> friends;
}
Restcontroller : I am requesting the getFriendsAtDistanceK.
#RestController
public class FriendsController {
#Autowired
private FriendsService friendsService;
#PostMapping("/friends")
public Friends createFriends(#RequestBody Friends frnd)
{
return friendsService.createFriends(frnd);
}
#GetMapping("/friends/{id}/distance/{k}")
public List<Friends> getFriendsAtDistanceK(#PathVariable("id") Long id,#PathVariable("k") int k)
{
return friendsService.getFriendsAtDistanceK(id, k);
}
}
I am raising the request as friends list have already existed friends. I want to create a relation which have new friends with existed friends entry. Request is given below that has id 4 and id 2 existed friends.
{
"name": "ajay",
"friends": [
{
"id":4,
"name": "amit",
"friends": null
},
{
"id":2,
"name": "amar",
"friends": null
}
]
}
I am getting the column 'id' not found exception.
java.sql.SQLException: Column 'id' not found.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.28.jar:8.0.28]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.28.jar:8.0.28]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89) ~[mysql-connector-java-8.0.28.jar:8.0.28]
your help is appreciated.

Related

Post JSON with #ManyToOne Relationship in Spring Boot

I have written a test application in spring boot. Employees have a relation to a department. CRUD works, but I'm not sure I'm doing it the correct way.
When I will create a new employee I have to send the following post request
"id": 3,
"firstname": "John",
"lastname": "Doe",
"salary": 50000,
"department": {
"id": 2,
"name": "Sales"
}
}
This is the employee class:
#Entity
public class Employee {
#Id
#GeneratedValue
private Long id;
private String firstname;
private String lastname;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "department_id", referencedColumnName="id")
private Department department;
private int salary;
This is the create method in the EmployeeController:
#PostMapping("/employees")
public Employee create(#RequestBody Employee employee) {
return employeeService.add(employee);
}
The department entries already exists.
Is it possible to create an employee without filling the complete relation
(department)?
I would like to add the department id only. But if I do this, the name field in the json data is empty (get request)
id 3
firstname "John"
lastname "Doe"
department
id 2
name null
salary 50000
Is there any better approach?
You are taking an Entity as a request body which is not the correct approach. You can take Some VO as Request Object and then convert to Entity inside a service.
For E.g
EmployeeVO{
private String firstname;
private String lastname;
List<Integer> departments;
}
Also, you can use Jackson annotations like
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL) to ignore unknown attributes and include not null attributes.

JPA serialize enttiy

I have my data model that contains 3 tables: User, Profile, UserProfile.
public class User implements Serializable {
private Integer id;
......
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch =
FetchType.LAZY)
#JsonManagedReference
#JsonProperty("profiles")
private List<UserProfile> userProfiles = new ArrayList<UserProfile>();
}
public class Profile implements Serializable {
private Integer id;
......
#OneToMany(mappedBy="profile", cascade = CascadeType.ALL, fetch =
FetchType.LAZY)
#JsonBackReference
private List<UserProfile> userProfiles= new ArrayList<UserProfile>();
}
public class UserProfile implements Serializable {
private Integer id;
#ManyToOne
#JoinColumn(name = "idUser")
#JsonBackReference
private User user;
#ManyToOne
#JoinColumn(name = "idProfile")
#JsonManagedReference
private Profile profile;
}
And here’s my json feed back:
{
"id": 1,
.......
"profiles": [
{
"profile": {
"id": 1,
.....
},
{
"id": 2,
.....
}
}
]
}
I have two questions:
Is it possible to remove the profile attribute and have:
{
"id": 1,
.......
"profiles": [
{
"id": 1,
.....
},
{
": 2,
.....
}
]
}
In a manytomany relationship with an intermediate table that contains a primary key (id), 2 foreign key that are the ids of the 2 tables that have the manytomany relationship, is that how to do it?
For the 1st question, to hide profile attribute, there are 2 options:
1. If you don't need it in any json output, you can add a #JsonIgnore annotation to it;
2. If you need it elsewhere but don't want it here, you can use Projection. Check https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections and https://www.baeldung.com/spring-data-rest-projections-excerpts for reference on how to use projections.
Checked your code again. Your code has some problem.
You only need 2 entities: User and Profile. And just add #ManyToMany relationship to them.
Refer here for a complete sample on ManyToMany https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

How can I create Join table in MySQL database using hibernate in Java?

I have two entity table called appointment and service. One appointment can be many services. Services already store in the database. We can newly add appointment. When add new appointment we selected added services from the drop down menu. Can add many services with one appointment. I need to store new record on appointment table and store relevant appointment id and services id's on another join table. Here attached image with my problem.
Already I tried many ways for do this. Bellow is one attempt.
Here is appointment class
#Entity
#Table(name="appointment")
public class Appointment extends AbstractPersistable<Long> implements Serializable {
#OneToMany
#JoinTable(name = "service_x_appointment", joinColumns = #JoinColumn(name = "appointment_id"),
inverseJoinColumns = #JoinColumn(name = "beautyservice_id"))
Set<BeautyService> beautyServices;
private String type;
private Date date;
private String time;
private String description;
private int approval;
#ManyToOne
#JoinColumn(name = "userid")
private User user;
//getter and setter
}
Here is BeautyService class
#Entity
#Table(name="beauty_service")
public class BeautyService extends AbstractPersistable<Long> {
private String serviceName;
private String timeDuration;
private String amount;
//getter and setter
}
Here is appointment controller class code,
#RequestMapping(value="/createAppointment",method = RequestMethod.POST)
public String createAppointment(#RequestBody Appointment appointment){
String response = null;
response = appointmentService.save(appointment);
return response;
}
Here is appointment service class code
public String save(Appointment appointment) {
appoinmentRepository.save(appointment);
return "Appointment added successfully";
}
Here is the my request body.
{
"type":"Type02",
"date":null,
"time":"20:56",
"description":"Hellow World",
"approval":0,
"user":{
"id":2,
"name" : "Alex",
"telephone" : "0774466886",
"age":21,
"email": null
},
"beautyServices" : [
{
"id":1,
"serviceName":"hair strate",
"timeDuration" : "02 Hours",
"amount" : 5000
},
{
"id":2,
"serviceName":"Eye brows",
"timeDuration" : "02 Hours",
"amount" : 5000
},
{
"id":3,
"serviceName":"Near cutting",
"timeDuration" : "02 Hours",
"amount" : 5000
}
]
}
Why not record in the join table? Only appointment table.
You can do it in multiple ways. One has been specified #Aritra Paul, which is actually Bidirectional representation of OneToMany mapping.
I think you want to use UniDirectional representation. In that case you won't have to use mappedBy.
Just create your entities like below:
#Entity
#Table(name="appointment", schema="ADMIN")
public class Appointment implements Serializable {
#OneToMany
#JoinColumn(name = "appointment_id")
#JoinTable(name = "service_appointment", joinColumns = #JoinColumn(name = "appointment_id"),
inverseJoinColumns = #JoinColumn(name = "service_id"))
Set<Service> services;
}
#Entity
public class Service {
// Some Properties. No need to specify reference of Appointment here.
}
If you define your entities like that you will have a join table like this
+----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------+------+-----+---------+-------+
| appointment_id | bigint(20) | NO | MUL | NULL | |
| service_id | bigint(20) | NO | PRI | NULL | |
+----------------+------------+------+-----+---------+-------+
Hope this helps!!
You definitely shouldn't create Joined table entity as you mentioned as it's more the underlying database representation than the object oriented one.
You can achieve the join table by defining something like:
#Entity
#Table(name="appointment", schema="ADMIN")
public class Appointment implements Serializable {
//...
#OneToMany(mappedBy="appointment")
#JoinTable(name="Join_Table")
Set <ServiceT> service;
use relation mapping ManyToOne or OneToMany according to your table.
#Entity
#Table(name="service", schema="ADMIN")
public class ServiceT implements Serializable {
//...
#ManyToOne
Appointment appointment;
If you want to explicitely set your column name you can use
#JoinColumn
annotation.
Can you please check if the beautyServices are actually being bound from the #RequestBody properly.
The property name is beautyServices while in Json it says "service".
In the Json it should say "beautyServices" instead of "service".
Also, check if the ids 1, 2, 3 already pre-exists on the beautyServices table.
If Not, if you want those to get inserted as well by saving appointment, you need to add CASCADETYPE.PERSIST.

Spring Data, MySQL and not working unique value

I'm having troubles getting into Spring Data
I got entity Product which has Category (I'm guessing relation type is right? Product has one Category, Category has many products)
#Entity
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "category_id")
private Category category;
}
#Entity
class Category implements Serializable {
public Category() {
}
public Category(String name){
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Long id;
#Column(unique = true)
private String name;
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Product> products;
}
Now I try to add new Product via Postman, calling my RestController
#PostMapping("/add")
public Product addProduct(#Valid #RequestBody Product product){
return repository.save(product);
}
With 2 following requests
{
"name" : "pork",
"category" : "meat"
}
{
"name" : "chicken",
"category" : "meat"
}
In the result I got 2 following responses
{
"id": 1,
"name": "pork",
"category": {
"id": 1,
"name": "meat",
"products": null
}
}
{
"id": 2,
"name": "chicken",
"category": {
"id": 2,
"name": "meat",
"products": null
}
}
And on database I actually got 2 categories named "meat" (even tho it should be unique. What's more, do I actually need Set<Product> in my Category class? TBH, Category has no intrest in that at all.
There are a few problems with your code.
You are directly using entity as the rest API model. Suggest to create a separate ProductModel with only fields that client has access to.
You mixing category creation together inside product creation, but your category in the request only contains name. To the backend, unless you check whether such a category exists, it's always treated as a new category.
Before you call repository.save, you need let category knows what's the product inside. In your current code, only product know its category.
You don't need Set products in your Category class (and it's recommended to use only #ManyToOne).

Retrieving details from multiple tables using SpringMVC

I am developing a Shopping Application, In my Application i have table tenant and in tenant table i have have column Binary_id which is primary key in binary table in database. Now when i making a get request to tenant table i am getting all the tenant table fields as JSON. But I have #ManyToOne relation from binary table to tenant i.e tenant can have multiple records in binary. So, while making GET call from POSTMAN client instead of getting tenant details, i need to get all the binary records related to that tenant as JSON.
Now i am getting JSON as follows when making a call to http://localhost:8080/sportsmvc/rest/tenant from POSTMAN Client
[
{
"id": 2,
"binaryId": "1002",
"name": "AltisArena"
},
{
"id": 9,
"binaryId": "1001",
"name": "Agon"
}
]
But i need the responce JSON As below:
[
{
"id": 2,
"name": "AltisArena",
"listOfBinary": [
{
"tenant_id": 2,
"location": "location1",
"description": "ABC"
},
{
"tenant_id": 2,
"location": "location2",
"description": "ABCD"
}
]
},
{
"id": 9,
"name": "Agon",
"listOfBinary": [
{
"tenant_id": 9,
"location": "location3",
"description": "desc1"
},
{
"tenant_id": 9,
"location": "location4",
"description": "desc2"
}
]
}
]
Code snippets:
Tenant Entity:
#Entity
#Table(name="tenant", catalog="db_sports" )
// Define named queries here
#NamedQueries ( {
#NamedQuery ( name="TenantEntity.countAll", query="SELECT COUNT(x) FROM TenantEntity x" )
} )
public class TenantEntity implements Serializable {
private static final long serialVersionUID = 1L;
//----------------------------------------------------------------------
// ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD )
//----------------------------------------------------------------------
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id", nullable=false)
private Integer id ;
#Column(name="name", nullable=false, length=300)
private String name ;
//----------------------------------------------------------------------
// ENTITY LINKS ( RELATIONSHIP )
//----------------------------------------------------------------------
#ManyToOne
#JoinColumn(name="binary_id", referencedColumnName="id")
private SwaBinaryEntity swaBinary ;
SWA_Binary Entity:
#Entity
#Table(name="SWA_Binary", catalog="db_sports" )
// Define named queries here
#NamedQueries ( {
#NamedQuery ( name="SwaBinaryEntity.countAll", query="SELECT COUNT(x) FROM SwaBinaryEntity x" )
} )
public class SwaBinaryEntity implements Serializable {
private static final long serialVersionUID = 1L;
//----------------------------------------------------------------------
// ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD )
//----------------------------------------------------------------------
#Id
#Column(name="id", nullable=false, length=100)
private String id ;
#Column(name="file_location", nullable=false, length=400)
private String fileLocation ;
#Column(name="description", nullable=false, length=200)
private String description ;
TenantRestController:
#RequestMapping( value="/tenant",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public List<Tenant> findAll() {
return tenantService.findAll();
}
TenantServiceImpl:
#Override
public List<Tenant> findAll() {
List<TenantEntity> entities = tenantPersistence.loadAll();
List<Tenant> beans = new ArrayList<Tenant>();
for(TenantEntity entity : entities) {
beans.add(tenantServiceMapper.mapTenantEntityToTenant(entity));
}
return beans;
}
TenantServiceMapper:
public Tenant mapTenantEntityToTenant(TenantEntity tenantEntity) {
if(tenantEntity == null) {
return null;
}
//--- Generic mapping
Tenant tenant = map(tenantEntity, Tenant.class);
//--- Link mapping ( link to SwaBinary )
if(tenantEntity.getSwaBinary() != null) {
tenant.setBinaryId(tenantEntity.getSwaBinary().getId());
}
return tenant;
}
Can anyone please help to to solve this issue.
Thanks in Advance.
Maybe I misunderstood model, but it seems like it's a bit wrong. In what you need JSON you have tenant that have multiple binaries, but in JPA model it's vise versa and tenant have 1 binary.
In TenantEntity shouldn't it be like this ?:
#OneToMany
private List<SwaBinaryEntity> swaBinary