We have Spring Boot 2.x, Spring Data and PostgreSQL as database.
In our application we have Driver class as below
#Data
#Entity
public class Driver {
private String id;
private String name;
private String licenseNo;
}
Now a car can be driven by many drivers. So we have Car class as below.
#Data
#Entity
public class Car {
private String id;
private String number;
private String registrationNumber;
#OneToMany(fetch = FetchType.LAZY)
private List<Driver> drivers;
}
Whenever we fetch drivers from car object we get drivers not ordered by id in ascending, seems like it orders by name or id in descending order.
Is there any way in JPA where we can specify the default order by when we map.
Thanks
Hi,you add a annotation in drivers field.
show code.
#Data
#Entity
public class Car {
private String id;
private String number;
private String registrationNumber;
#javax.persistence.OrderBy("id ASC")
#OneToMany(fetch = FetchType.LAZY)
private List<Driver> drivers;
}
order option`s 'ASC' 'DESC',default is ASC
exsmple:
#javax.persistence.OrderBy("id")
#javax.persistence.OrderBy("name")
or:
#javax.persistence.OrderBy("id DESC")
#javax.persistence.OrderBy("name DESC")
Related
#Entity
public class ClassA {
some attributes
#Enumerated(value = EnumType.STRING)
private EnumObject status;
}
My Enum:
public enum EnumObject {
OK,
BAD,
SOME_CASE,
ANOTHER_CASE;
There are a possibility to say never return Entity when status=BAD for all queries
Kindly see if the below notions help you in achieving what you are after:
2.3.21. #Where
Sometimes, you want to filter out entities or collections using custom
SQL criteria. This can be achieved using the #Where annotation, which
can be applied to entities and collections.
Example 78. #Where mapping usage
public enum AccountType {
DEBIT,
CREDIT
}
#Entity(name = "Client")
public static class Client {
#Id
private Long id;
private String name;
#Where( clause = "account_type = 'DEBIT'")
#OneToMany(mappedBy = "client")
private List<Account> debitAccounts = new ArrayList<>( );
#Where( clause = "account_type = 'CREDIT'")
#OneToMany(mappedBy = "client")
private List<Account> creditAccounts = new ArrayList<>( );
//Getters and setters omitted for brevity
}
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-column-where
2.3.23. #Filter
The #Filter annotation is another way to filter out entities or
collections using custom SQL criteria. Unlike the #Where annotation,
#Filter allows you to parameterize the filter clause at runtime.
Now, considering we have the following Account entity:
Example 85. #Filter mapping entity-level usage
#Entity(name = "Account")
#FilterDef(
name="activeAccount",
parameters = #ParamDef(
name="active",
type="boolean"
)
)
#Filter(
name="activeAccount",
condition="active_status = :active"
)
public static class Account {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
private Client client;
#Column(name = "account_type")
#Enumerated(EnumType.STRING)
private AccountType type;
private Double amount;
private Double rate;
#Column(name = "active_status")
private boolean active;
//Getters and setters omitted for brevity
}
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-column-filter
Also take a look at Global hibernate filter on all database queries which uses AspectJ to intercept the queries if you want to do it in another way.
I have a Class which has other objects as it's members fields.
e.g.:
class Orders{
private Integer code;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name="code", nullable=false)
private Category category;
private PaymentType pt;
}
class Category{
private Integer id;
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name="id", nullable=false)
private Brands brand;
....
}
class Brands{
private Integer id;
private String brandName;
}
I need to get all the Brands for that particular order.
How do I get just the brands through Orders table in Hql?
Are the relations one-to-one? If so, you should be able to query it with:
#Query("SELECT FROM Orders orders.category.brand WHERE ...")
Brands findBrandBy(...);
if you are using Spring data.
I am using Spring-Boot with JPA and a MySQL backend. Now I got quite confused about the repositories Spring-Boot provides. I know these are quite powerful (and seem to be quite useful since they can shorten your code a lot). Still, I do not understand how to represent Joins within them, since the result-set should be a combination of specified attributes in the select of a few Entities.
Now let's assume we have three tables Book, Author, AuthorOfBook, where the last one is simply connecting Book and Author by a combined Primary key. I guess we had the following Java-Classes:
Entity Book:
#Entity
#Table(name="BOOK")
public class Book {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "TITLE")
private String title;
}
Entity Author
#Entity
#Table(name="AUTHOR")
public class Author {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "FIRSTNAME")
private String firstname;
//Let's assume some getters and setters and a constructor
}
Entity AuthorOfBook:
#Entity
#Table(name="BOOK")
public class Book {
#EmbeddedId
private AuthorOfBookId pk;
}
An Embedded ID
#Embeddable
public class AuthorOfBookId implements Serializable {
private int authorId;
private int bookId;
}
Repository
#Repository
public interface AuthorOfBookRepository extends JpaRepository<,AuthorOfBookId> {
}
Now how would I represent that query:
SELECT b.name, a.firstname, a.lastname from AuthorOfBook ab inner join Book b on b.id = ab.book_id inner join Author a on a.id = ab.author_id where a.lastname = :lastname;
in my repository? I know the signature would need to be like
#Query([the query string from above])
public (...) findAuthorAndBookByAuthorLastname(#Param("lastname") String lastname);
but I cannot make out what Type the return would be like. What is that method returning? (simply AuthorOfBook would not work I guess)
You don't want AuthorOfBook as a separate Entity. Book should have a field of type Author as a #ManyToOne relationship. That way, given any Book, you can find the author's details.
If you want to handle audits fields you can do something like this:
Audit class
#Embeddable
public class Audit {
#Column(name = "created_on")
private Timestamp createdOn;
#Column(name = "updated_on")
private Timestamp updatedOn;
#Column(name = "is_deleted")
private Boolean isDeleted;
//getters and setters
}
AuditListener to update automatically audits fields
public class AuditListener {
private Long loggedUser = 1001L;
/**
* Method to set the fields createdOn, and isDeleted when an entity is persisted
* #param auditable
*/
#PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if (audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setIsDeleted(Boolean.FALSE);
audit.setCreatedOn(Timestamp.from(Instant.now()));
}
/**
* Method to set the fields updatedOn and updatedBy when an entity is updated
* #param auditable
*/
#PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(Timestamp.from(Instant.now()));
}
}
And add this to the entities
#EntityListeners(AuditListener.class)
public class Book implements Auditable {
#Embedded
private Audit audit;
I have what I thought was a straight forward relation in JPA. Looks like this. CompanyGroup:
#Entity
#Table
public class CompanyGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
#Column(name = "name")
private String name;
#JoinColumn(name = "companies")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Company> companies;
}
Company:
#Entity
#Table
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "name")
private String name;
#JoinColumn(name = "users")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<User> users;
#Id
#GeneratedValue
private Long id;
}
User:
#Entity
#Table
public class User {
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "email")
private String email;
#Id
#GeneratedValue
private Long id;
}
I have omitted setters, getters, etc.
This is not working. I'm trying to save a CompanyGroup(Has 2 companies, each company has 2 users, all entities are unique) to a fully empty database.
I persist this using Spring-Data, accessed in a service like this:
#Service
public class ConcreteCompanyGroupService implements CompanyGroupService {
#Autowired
private CompanyGroupRepository repository;
#Transactional
#Override
public void save(CompanyGroup group) {
repository.save(Collections.singleton(group));
}
}
When I try to call this method I receive this:
org.postgresql.util.PSQLException: ERROR: syntax error at or near "User"
Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2158)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:291)
Hopefully I have done something stupid that someone can find quickly. I don't know how to solve this.
EDIT:
The driver in my pom.xml:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1211</version>
</dependency>
Your entity maps across to a table name that is an SQL reserved keyword (User). Sadly for you, your chosen JPA provider does not automatically quote the table name identifier, and so you get exceptions when referring to the table.
Solution is either to quote the table name yourself in the #Table annotation, or change the table name to not be a reserved keyword. Alternatively use a JPA provider that auto-quotes such reserved keywords for you (e.g DataNucleus)
Solution 1: As Pascal mentioned, you have to escape the table name with backslash like:
#Entity
#Table(name="\"User\"")
public class User {
...
}
Solution 2: Rename your table's anme with another name (Users)
#Entity
#Table(name="Users")
public class User {
...
}
Solution 3: Add a suffix to the table's name:
#Entity
#Table(name="APP_User")
public class User {
...
}
Solution 4: Change the entity name, e.g. ApplicationUser
#Entity
public class ApplicationUser {
...
}
The reason
PostgreSQL as some reserved SQL Key Words. For example: ABORT, ALL, ARRAY, CACHE, CUBE, USER, ... Those tokens are in the SQL standard or specific to PostgreSQL
Use the #Table annotation or change your class name from User to something else as User is a reserved keyword in sql.
I'm using spring-data-mongodb 1.8.2 (spring-boot-starter 1.3.1) and I have a fairly easy case at hand (in which I added fetch eager in desperation):
#Document(collection = "class_room")
public class ClassRoom implements Serializable {
#Id
private String id;
#NotNull
#Field("name")
private String name;
#ManyToOne**(fetch = FetchType.EAGER)**
#JoinColumn(name = "school_id")
private School school;
[...]
}
#Document(collection = "school")
public class School implements Serializable {
#Id
private String id;
#NotNull
#Field("name")
private String name;
#OneToMany(mappedBy = "school"**, fetch = FetchType.EAGER**)
private Set<Article> articles = new HashSet<>();
[...]
}
The repositories:
public interface SchoolRepository extends MongoRepository {
}
public interface ClassRoomRepository extends MongoRepository<ClassRoom,String> {
}
And the resources:
#RequestMapping(value = "/schools",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<School> getAllSchools() {
return schoolRepository.findAll();
}
#RequestMapping(value = "/classRooms",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<ClassRoom> getAllClassRooms() {
return classRoomRepository.findAll();
}
Now, can someone explain to me why the articles are correctly loaded when I perform the 'schoolRepository.findAll()'
but not when I perform the 'classRoomRepository.findAll()'?
And how can I make it happen?
TL;DR
A School has set of Articles
A classRoom has a School.
When I access a school directly: I see the set of Article
When access a school through a classRoom, the set of Article is empty.
Your approach to using object associations is a bit off. In Spring Data with Mongo the concepts of defining annotations to describe how associations happen is not the standard approach.
If you see the documentation here http://docs.spring.io/spring-data/data-mongo/docs/1.4.2.RELEASE/reference/html/mapping-chapter.html it helps to provide more clarity.
But to highlight, Mongo uses the concept of embedded objects and so ideally your data structure can be something like:
#Document(collection = "class_room")
public class ClassRoom implements Serializable {
#Id
private String id;
private String name;
private School school;
// Where School has the following fields and structure:
// private String id;
// private String name;
// private Set<Article> articles = new HashSet<>()
}
If you want school to be embedded in ClassRoom you leave it as above, else you can have School as a separate collection of its own. So:
#Document(collection = "school")
public class School implements Serializable {
#Id
private String id;
private String name;
private Set<Article> articles = new HashSet<>();
[...]
}
In the above School, it is a collection of its own and is not embedded in ClassRoom.
Typically, you have to just think differently from your traditional ORM approach when dealing with Mongo, or a NoSQL/Graph database.