Retrieve the record using Spring Data JPA - spring-boot

I'm having spring data jpa repository.I the entity contain primary key id int and ipaddress string. The table contain only 1 record at a time otherwise null.
How do i retrieve the record using JPA , if it is not found return null.
#Repository
public interface IpConfigRepository extends JpaRepository<IpConfig, Integer> {
//
IpConfig findIpConfig();
}

According to the naming convention, you should define the method with the name findById(Integer id) ( assume the Id is the primary key )

Suppose you have a class A as shown below
class A{
private int id;
private String data;
// getters and setters
}
You can now search the items by the following ways.
public interface ARepo extends JpaRepository<A,Integer>{
// get all the records from table.
List<A> findAll();
// find record by id
A findById(int id);
// find record by data
A findByData(String data);
// find by date created or updated
A findByDateCreated(Date date);
// custom query method to select only one record from table
#Query("SELECT * FROM a limit 1;")
A findRecord();
}

Related

Spring JPA Two Entities for same DB table

I am writing Spring Boot Data JPA application and I have following situation:
I have 2 database queries fetching from same table but they are fetching different columns and data based on their WHERE clauses. For example:
SELECT CAR_TYPE, CAR_MODEL, CAR_YEAR, ACCIDENT_YEAR, BUY_DAY FROM CAR WHERE ACCIDENT_YEAR IS NULL
, and
SELECT CAR_MODEL, CAR_YEAR FROM CAR WHERE CAR_YEAR >= CURRENT_YEAR
As you can see these 2 queries (whose results will be exposed through 2 different API points) reference the same table CAR, but return different fields and have different WHERE clauses.
I know in JPA, I have to create an entity CarEntity like:
#Entity
#Table(name = "CAR")
public class CarEntity {
// I can only have fields from one or the other query
// here, so I guess I have to have 2 of these
}
, but my problem is that this entity needs to apply for the 2 different queries (with different fields returned, different data, different WHERE clauses).
So, it looks like I have to have actually 2 CarEntity classes. But, I am not sure how to make these 2 CarEntities so they both reference the same table CAR?
You can do by using projection that basically you define an interface with field methods which you want to get them. Projections
#Entity
public class Car implement CarSummary { // if you want you can implement JIC
private UUID id;
private String carType;
private String carModel;
private LocalDateTime carYear;
//getters and setters
}
public interface CarSummary {
String getCardModel();
String getCarYear();
}
Then on your query.
public interface CarRepository extends Repository<Car, UUID> {
Collection<CarSummary> findByCarYearGreaterThan(LocalDateTime now);
Collection<Car> findByAccidentYearIsNull();
}

Spring Data JDBC One-To-Many with Custom Column Name

I'm using spring-boot-starter-data-jdbc 2.4.2. In my domain aggregate I need to map a List of Strings that is populated from a column in another table. It is a legacy database so I have no control over the table and column names and need to use custom names. I see there is an #MappedCollection annotation, but can't see how to use it in this scenario. Below is my class:
#Data
#Table("NMT_MOVIE_THEATRE")
public class MovieTheatre {
#Id
#Column("MOVIE_THEATRE_ID")
private Long id;
#Column("ZIP_CODE")
private String zipCode;
// this comes from table NMT_CURRENT_MOVIE, column CM_ID, joined by MOVIE_THEATRE_ID
private List<String> currentMovieIds;
}
Using Spring Data JDBC, how can I create the one-to-many relation?
Wrap your String in a little entity.
#Table("NMT_CURRENTMOVIE")
class MovieId {
#Id
#Column("CM_ID")
final String id
// add constructor, equals and hashCode here or generate using Lombok
}
Then use it in the MovieTheatre. Since you don't have a column for an index, the proper collection to use is a Set
// ...
class MovieTheatre {
// ...
#MappedCollection(idColumn="MOVIE_THEATRE_ID")
Set<MovieId> currentMovieIds;
}
Note that equals and hashCode is important as well as the constructor taking all arguments used in those, since the entity is used in a Set.

Spring-boot jpa how to find entity with max value

Lets tell I have two tables.
CREATE TABLE user (ID int AUTO_INCREMENT,PRIMARY KEY (ID));
CREATE TABLE points (ID int AUTO_INCREMENT, user_id int, points int,PRIMARY KEY (ID));
How can I use spring-boot jpa to request user and max points like this?
select u.ID,max(p.points) from user u, points p where u.id=p.user_id
Or any alternatives to solve this kind of problems?
Assuming you have a Repository of User:
public class User {
private int id;
private List<Point> points;
...
}
With a relationship to the Points object:
public class Point {
private int id;
private User User;
private int points;
...
}
I haven't tested, but you should be able to do:
User findFirstByIdOrderByPointPointsDesc(int userId)
Similar to example 18 in the docs.
The only problem you have, regardless of the query or Spring Data, is if you have two users with the same point values. If you need more logic around tie-breaking, it might be more worth it to write a #Query (with your query, plus the extra tie-breaking logic) or a #NativeQuery.
I usually create a class to hold result such as
public class Result {
private User user;
private int votes;
// getters and setters
}
And write a custom query in the repository to fetch the data
#Query(value = "SELECT new com.package.Result (u, MAX (p.points) )
FROM user u
JOIN points p
ON u.id = p.user_id
GROUP BY u")
List<Result> getPointsPerUser();
Replace com.package.Result with appropriate path to the Result class.
Below method can be written in Repo and used as Transaction as in dao layer, which will be accessible from service layer.
#Query(value = "SELECT max(transactionId) FROM TransactionPayloadInfo")
int getMaxTransactionId();
create a model of data.
public class Data {
private int id;
private int maxPoints;
// getters and setters method
}
And write your query like this for getting model of Data.
#Query(select packagename.Data(u.ID,max(p.points) ) from user u, points p where u.id=p.user_id)
Data findUserWithMaxVots();

How to query a database having a composite key, which accepts queries where parts of the composite key are null in Spring JPA?

I have a webapp that uses a database with a composite key. I need to create an API which will accept the parameters of the composite key wherein each paramenter can be null.
(for eg. If all the parameters of the composite key are set as null and query is done, then it should just return all rows in db)
I have used QueryByExampleExeccutor but it keeps throwing a null pointer exception.
Below is the model indicative of 1 row of the DB
public class Row
{
#EmbeddedId
private RowKey rowkey;
#Column
private String rowAttribute;
//getters and setters for rowkey and rowAttribute
}
Below is the model indicative of RowKey
public class RowKey
{
#Column(name = "rowBlock")
private String rowBlock;
#Column(name = "rowSection")
private String rowSection;
//getters and setters for above fields
}
I'm using QueryByExampleExecutor by extending my Repository(or DAO) with it as
public interface RowRepo extends CrudRepository<Row, RowKey>, QueryByExampleExecutor<Row> {
}
In my service layer I use the following statement to call repo methods to return a list of matched rows from DB
public List<Row> getRowRangeQuery(rowBlock,rowSection,rowAttribute)
{
Row row = new Row(new RowKey(rowBlock,rowSection),rowAttribute);
List<Row> Result = (List<Row>)getRowRepository().findAll(Example.of(row));
return Result;
}
I get an InvocationTargetException which when unrolled reveals a null pointer Exception at rowSection.

How to handle DataIntegrityVilolationException while saving a list in Spring Data JPA?

I am using Spring Data JPA in a Spring Boot Application, with MYSQL. There I am saving a list of entities with unique constraint over a field. Out of the list of entities, there is one entity that will throw DataIntegrityViolationException due to the unique constraint. I noticed that none of the entities get persisted in that case, even those that does not violate the unique constraint.
What should be the ideal approach in this case so that those entities which do not violate the unique get persisted ?
Of course I can iterate the list and save them one by one. In fact that is what SimpleJpaRepository is doing underneath.
#Transactional
public <S extends T> List<S> save(Iterable<S> entities) {
List<S> result = new ArrayList<S>();
if (entities == null) {
return result;
}
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
My code - Entity :
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = { "name" }, name = "uq_name"))
public class SampleContent {
#Id
#GeneratedValue
private Long id;
private String name;
//getter setters
}
Repository :
public interface SampleContentRepository extends JpaRepository<SampleContent, Serializable>{
}
JUnit test :
#Test
public void testCreate(){
List<SampleContent> sampleContentList = new ArrayList<>();
SampleContent sampleContent1 = new SampleContent();
sampleContent1.setName("dd");
SampleContent sampleContent2 = new SampleContent();
sampleContent2.setName("Roy");
SampleContent sampleContent3 = new SampleContent();
sampleContent3.setName("xx");
sampleContentList.add(sampleContent1);
sampleContentList.add(sampleContent2);
sampleContentList.add(sampleContent3);
try{
this.sampleContentRepository.save(sampleContentList);
}catch(DataIntegrityViolationException e){
System.err.println("constraint violation!");
}
}
There is an entity with name "Roy" already present in the table. So, the entire transaction fails and #Transactional rolls back.
I think you can use next steps:
Load existing entities from DB into Set
Override equals and hashCode methods based on name
call Set::addAll you antities (or just add them one by one)
save that Set to DB
Maybe it's suboptimal because forces you to make select * query. But I think it's much more effective then saving entities one by one to DB.
Accotding to this article you can use name as your business key, which has lots of benefits.

Resources