find by property name in JPA repository returns the value of first row alone - spring-boot

I am new to spring boot and was trying to implement an sales related application. There i implemented a custom findBy method using property name customer id . The following is the output i am getting
[{"customerId":101,"stockId":1},{"customerId":101,"stockId":1},{"customerId":101,"stockId":1},{"customerId":101,"stockId":1}]
which is actually the first row but the values in table is different.
CUSTOMER_ID STOCK_ID
101 1
101 2
101 3
101 4
102 1
103 2
103 3
104 4
Since it is a sample start up application i didnt specify any constraints. what i am doing wrong here.
Update:
this is my Repository
#Repository
public interface CustomerSalesRepo extends JpaRepository<CustomerSales,Integer> {
public List<CustomerSales> findAllByCustomerId(int custID);
}
this is my sales entity
#Entity
#Table(name = CustomerSales.TABLE_NAME)
public class CustomerSales {
public static final String TABLE_NAME= "CUSTOMER_SALES";
#Id
#Column(name="CUSTOMER_ID")
private int customerId;
#Column
private int stockId;
data.sql
DROP TABLE CUSTOMER_SALES IF EXISTS;
CREATE TABLE CUSTOMER_SALES (customer_Id INT, stock_Id INT);
INSERT INTO CUSTOMERSALES (customer_Id,stock_Id)VALUES (101,1),(101,2),(101,3),(101,4),(102,1),(103,2),(103,3),(104,4);

I am not sure how you were able to populate that data set into your DB table since there is a primary key on customerId only. That means that you cannot have more than 1 row with CUSTOMER_ID = 101.
You should define a composite PK class
public class CustomerSalesPk implements Serializable
{
private int customerId;
private int stockId;
public int getCustomerId()
{
return customerId;
}
public void setCustomerId(final int customerId)
{
this.customerId = customerId;
}
public int getStockId()
{
return stockId;
}
public void setStockId(final int stockId)
{
this.stockId = stockId;
}
}
Then use this PK class in your entity
#Entity
#Table(name = CustomerSales.TABLE_NAME)
#IdClass(CustomerSalesPk.class)
public class CustomerSales
{
public static final String TABLE_NAME = "CUSTOMER_SALES";
#Id
#Column(name = "CUSTOMER_ID")
private int customerId;
#Id
#Column(name = "STOCK_ID")
private int stockId;

Related

JPA JoinTable with additional columns

Spring Boot
Spring Data
JPA Hibernate
Came across a requirement where JPA ManyToMany relationship table with an extra column. Have looked at StackOverflow and found several questions related to same requirement. Most of the answers on the forums ask for EmbeddedId field with a composite primary key with two columns. I tried the solutions from the forums, here is the code snippet.
#Data
#Entity
#Table (name = "TABLE_A")
public class TableA {
#Id
#Column (name = "table_a_id")
private Integer id;
...
#OneToMany (mappedBy = "pk.tableA")
private List<TableABMapping> mappingTable;
}
#Data
#Entity
#Table (name = "TABLE_B")
public class TableB {
#Id
#Column (name = "table_b_id")
private Integer id;
...
#OneToMany (mappedBy = "pk.tableB")
private List<TableABMapping> mappingTable;
}
#Data
#Entity
#Table (name = "TABLE_A_TABLE_B_MAPPING")
public class TableABMapping implements Serializable {
#EmbeddedId
private MappingKey pk = new MappingKey();
#Column(name = "addon_field")
private Double additionalField;
#Transient
public TableA getTableA() {
return getPk().getTableA();
}
public void setTableA(TableA tableA) {
getPk().setTableA(tableA);
}
#Transient
public TableB getTableB() {
return getPk().getTableB();
}
public void setTableB(TableB tableB) {
getPk().setTableB(tableB);
}
// equals() & hashCode() method override
}
#Data
#Embeddable
public class MappingKey implements Serializable {
#ManyToOne
#JoinColumn(name = "table_a_id", referencedColumnName = "table_a_id")
private TableA tableA;
#ManyToOne
#JoinColumn(name = "table_b_id", referencedColumnName = "table_b_id")
private TableB tableB;
// No argument constructor, two arguments constructor.
// equals() & hashCode() method override
}
Trying save operation from service class like this:
for (TableB tabB : tableA.getTableB()) {
TableABMapping abMapping = new TableABMapping();
abMapping.setTableA(tableA);
abMapping.setProduct(tabB);
abMapping.setAdditionalField(tabB.getAddonField());
if (tableA.getMappingTable() == null) {
tableA.setMappingTable(new ArrayList<TableABMapping>());
}
tableA.getMappingTable().add(abMapping);
}
TableA ta = tableARepository.save(tableA);
System.out.println("TableA.save(): " + ta);
Getting this error on save operation.
Unable to find TableABMapping with id MappingKey(tableA = TableA( ... ), tableB = TableB ( ... ))
Both the entities have proper ids at the time of saving the entity. But still it throws this error. Where I am making mistake?

JPA - How to create entities where EntityA saves list ids of another table

I have an EntityA , and EntityB.
EntityB is a master table.
EntityA can have multiple id's of Entity B. So A column of EntityA should hold list/set of ids of EntityB.
I should be able to query EntityA, to get list of Ids of EntityB.
Note: Many rows in EntityA can refer to same id of EntityB
I tried below, but it I don't see column
#OneToMany(mappedBy = "todo")
private List<ObjectStore> store = new ArrayList<>();
Please can I ask how to do this using Spring JPA.
EDIT:
#Entity
public class Dept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull(message = "name is mandatory")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull(message = "name is mandatory")
private String name;
#ElementCollection(targetClass=String.class)
#CollectionTable(name = "DEPT", joinColumns = #JoinColumn(name="id"))
private List<String> dept = new ArrayList<String>(4);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I observed that DEPT column got added to dept table. This is unwanted.
Use Case: Employee can hold list of departments. Many employee records, should be able to have same dept references.
You should change table name from "DEPT". Because #CollectionTable will create another embedded table with given name. In you case dept is already there so it will create new column in Dept.
// Employee Class
#ElementCollection(targetClass=String.class)
#CollectionTable(name = "DEPT_EMPLOYEE_MAPPING", joinColumns = #JoinColumn(name="Employee_id"))
#MapKeyJoinColumn(name="Dept_Id")
private Map<Dept,DeptEmployeeRelationData> depts;
//Dept class
#ElementCollection
#CollectionTable(name="DEPT_EMPLOYEE_MAPPING",joinColumns=#JoinColumn(name="Dept_Id"))
#MapKeyJoinColumn(name="Employee_Id")
Map<Employee, DeptEmployeeRelationData> employees;
#Embeddable
class DeptemployeeRelationData {
#Column(name="createdAt")
DateTime createdAt;
}
Your mapping is many to many.
Hope this will work!
I used
#ManyToMany
#OrderColumn
private List<String> dept = new ArrayList<String>(4);
and working as per my requirement
DEPT, EMPLOYEE , EMPLOYEE_DEPT created

MyBatis #Many / Spring-Boot

I'm beginner (sorry for my bad explanation, feel free to correct me) in MyBatis Spring-Boot, I have problem to understand and make it works #Many
I'm using 3 layer logic programming (Presentation Layer, Service Layer, Data Layer)
Thanks for your help :)
I have 3 Tables (it's TB_Products and not TB_Product as on the screenshot):
I would like to get data form table TB_Users and TB_Products to "put" it in DTO
I create 4 java object class SearchEntity, ProductEntity (for Data layer)
I create an interface SearchRepositoryMapper.
I also create a SearchService interface and SearchServiceImpl as well.
Java object class:
SearchEntity
public class SearchEntity implements Serializable{
private static final long serialVersionUID = -9143930742617602050L;
private String id;
private String firstName;
private String lastName;
private List<ProductEntity> products;
// Getters and Setters code .....
}
ProductEntity
public class ProductEntity implements Serializable{
private static final long serialVersionUID = -6525703679290992635L;
private String id;
private String productId;
private String product;
private String number;
private String date;
private String description;
// Getters and Setters code .....
}
SearchRepositoryMapper
public interface SearchRepositoryMapper {
// Get some fields from TB_Users and all fields from TB_Products
#Select("SELECT * FROM TB_Users WHERE id = #{id}")
#Results({
#Result(property = "id", column ="id"),
#Result(property = "firstName", column = "firstName"),
#Result(property = "lastName", column= "lastName"),
#Result(property = "products", javaType = List.class, column="id",
many = #Many(select = "getProductIdByUserId"))})
public SearchEntity findAllInfoByUserId(#Param("id") int id);
#Select("SELECT *, productId FROM TB_Products WHERE productId = #{id}")
public ArrayList<ProductEntity> getProductIdByUserId(#Param("id") int id);
// Find id by uderId and return null if it doesn't exist
#Select("SELECT id FROM TB_Users WHERE userId = #{userId}")
int findIdByUserId(#Param("userId") String userId);
}
SearchServiceImpl
#Service
public class SearchServiceImpl implements SearchService {
#Autowired
SearchRepositoryMapper searchRepository;
#Override
public SearchDto getAllInfoByUserId(String id) {
SearchDto returnValue = new SearchDto(); // Init returnValue as SearchDto
int searchId = searchRepository.findIdByUserId(id); // Init searchId with the TB_Users id
SearchEntity searchEntity = searchRepository.findAllInfoByUserId(searchId);
BeanUtils.copyProperties(searchEntity, returnValue);
return returnValue;
}
}
So when I execute the code and do a GET request I get this error message:
{
"message": "nested exception is org.apache.ibatis.executor.ExecutorException: Statement returned more than one row, where no more than one was expected."
}
I found out that come from the mapper and SearchEntity searchEntity = searchRepository.findAllInfoByUserId(searchId);
But i don't know how to resolve it. The way I wrote the code is wrong
Thanks to correct me
The exception clearly says that the query returns multiple results. Plese verify if the data in the table is correct.

Insert and update data automatically into SQL table from another table

I have 2 tables and I want to update the first table with data after that the second table will be updated automatically.
I'm a beginner in spring boot and I really need your help.
I could insert data from table 1 to table 2 but if I update some data from table 1 then table 2 coudn't be updated.
What can I do?
This is what I have done so far: The two entities of the tables and the service I worked with to insert data into table 2 from table 1.
Table 1:
#Entity
#Table(name = "formation")
public class Formation {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String cursus;
private String groupeaction;
private String module;
private String formateur;
#Temporal(TemporalType.DATE)
private Date date;
private Long nbrappart;
private Long nbrabsent;
private Long hf;
private Long jf;
private Long nbrheures;
private Long tauxh;
private Long ristourneprevis;
private Long couthebergttc;
private Long coutpausecafttc;
Table 2:
#Entity
#Table(name = "tablef")
public class Tablef {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String cursus;
private Long nbrappart;
private Long Sumnbrheures;
private Long Sumjf;
private Long jhf;
private String groupeaction;
the service i used :
public Boolean InserIntoTableF(Tablef tf) {
Long id = ThreadLocalRandom.current().nextLong();
tf.setId(id);
jdbc.execute("insert into tablef (id,cursus,groupeaction
,nbrappart,sumnbrheures,sumjf,jhf)\r\n" +
"select id,cursus,groupeaction,nbrappart,sum(nbrheures),sum(jf)
,sum(jf)*nbrappart\r\n" +
" from formation \r\n" +
"group by cursus ;");
return true;
}
The controller :
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api")
#PreAuthorize("hasRole('ADMIN')")
public class FormationController {
#Autowired
private FormationService formationservice;
#Autowired
private FormationRepository formationrepository;
#GetMapping("/formations")
public List<Formation> GetAll() {
return formationrepository.findAll();
}
#GetMapping("/formations/{id}")
public ResponseEntity<Formation> getFormationById(#PathVariable(value = "id") Long formationId)
throws ResourceNotFoundException {
Formation formation = formationrepository.findById(formationId)
.orElseThrow(() -> new ResourceNotFoundException("Formation not found for this id :: " + formationId));
return ResponseEntity.ok().body(formation);
}
#PostMapping("/formations")
public Formation createFormation(#Valid #RequestBody Formation formation) {
return formationrepository.save(formation);
}
// this is how i update my entity formation (table 1)
#PutMapping("/formations/{id}")
public ResponseEntity<Formation> updateFormation(#PathVariable(value = "id") Long formationId,
#Valid #RequestBody Formation formationDetails) throws ResourceNotFoundException {
Formation formation = formationrepository.findById(formationId)
.orElseThrow(() -> new ResourceNotFoundException("Formation not found for this id :: " + formationId));
formation.setCursus(formationDetails.getCursus());
formation.setGroupeaction(formationDetails.getGroupeaction());
formation.setModule(formationDetails.getModule());
formation.setFormateur(formationDetails.getFormateur());
formation.setDate(formationDetails.getDate());
formation.setNbrappart(formationDetails.getNbrappart());
formation.setNbrabsent(formationDetails.getNbrabsent());
formation.setHf(formationDetails.getHf());
formation.setJf(formationDetails.getJf());
formation.setNbrheures(formationDetails.getNbrheures());
formation.setTauxh(formationDetails.getTauxh());
formation.setRistourneprevis(formationDetails.getRistourneprevis());
formation.setCouthebergttc(formationDetails.getCouthebergttc());
formation.setCoutpausecafttc(formationDetails.getCoutpausecafttc());
final Formation updatedFormation = formationrepository.save(formation);
return ResponseEntity.ok(updatedFormation);
}
#DeleteMapping("/formations/{id}")
public Map<String, Boolean> deleteFormation(#PathVariable(value = "id") Long formationId)
throws ResourceNotFoundException {
Formation formation = formationrepository.findById(formationId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + formationId));
formationrepository.delete(formation);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
#PostMapping(value = "/fileupload")
public ResponseEntity<Formation> uploadFile(#ModelAttribute Formation formation) {
Boolean isFlag=formationservice.saveDataFromFile(formation.getFile());
if(isFlag) {
return new ResponseEntity<>(HttpStatus.OK);
}else
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
// here where i inser data from formation(table1) to tablef (table2)
#PostMapping(value = "/test")
public Boolean AddTf(Tablef tf) {
return formationservice.InserIntoTableF(tf);
}
}
If you use spring boot jpa to persist your data then you can have a look at JPA EntityListener and #PostPersist
#Entity
#EntityListeners(MyEntityListener.class)
public class MyEntity {
#Id
#GeneratedValue
private int id;
private String field;
public MyEntity() { }
}
The MyEntityListener impl
public class MyEntityListener {
#PostPersist
void onPostPersist(MyEntity myEntity) {
// save data to second table that needs an update on myEntity save
}
}

Spring Data JPA Hibernate - Extra elements appearing in #ManyToOne relationship

I have some entity classes which have a one-to-many - many-to-one relationship. I am using Spring and Hibernate.
Each TwoWayService has exactly 2 Services in my application.
Excerpts:
#Entity
#Table(name = "two_way_services")
public class TwoWayService {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "twoWayService",
fetch = FetchType.EAGER)
private List<Service> services;
public TwoWayService() {
services = new ArrayList<>();
// Add two as default
services.addAll(Arrays.asList(new Service(), new Service()));
}
public void setService1(Service service) {
services.set(0, service);
service.setTwoWayService(this);
}
public void setService2(Service service) {
services.set(1, service);
service.setTwoWayService(this);
}
...
}
#Entity
#Table(name = "services")
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#ManyToOne(optional = false)
#JoinColumn
private TwoWayService twoWayService;
public void setTwoWayService(TwoWayService twoWayService) {
this.twoWayService = twoWayService;
}
...
}
I am using Derby on the backend. The database schema is like this:
CREATE TABLE two_way_services (
id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
config_name VARCHAR(255) NOT NULL,
name VARCHAR(80),
admin_ip VARCHAR(32) NOT NULL,
connection_state INT NOT NULL
);
CREATE TABLE services (
id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
name VARCHAR(80),
type INT NOT NULL,
ruleset VARCHAR(255) NOT NULL,
two_way_service_id INT,
FOREIGN KEY (two_way_service_id) REFERENCES two_way_services(id) ON DELETE CASCADE
);
The repository interface:
public interface TwoWayServiceRepository extends Repository<TwoWayService, Integer> {
<S extends T> S save(S entity);
...
}
In my unit tests, I find that when I call findOne on a TwoWayService, I find that I have 4 Services instead of 2. Browsing the database directly shows the data as I would expect.
TwoWayService tws1 = repo.findOne(1); // get by id
assertThat(tws1.getServices().size()).isEqualTo(2); // fails, expected:<[2]> but was:<[4]>
Examining it in the debugger I see 4 elements in the services list: the two that I expect, plus 2 extra ones which are copies of the expected. I don't see where these are coming from. Why are these extra objects appearing in the list?
I am not sure but I think, it is because you add 2 services in the constructor and 1 in each setter. This makes 4 in total. You test for the amount of services, is that what you wanted to test?

Resources