I have a basic entity and I want to create a query that would retrieve this entity's members. Here is the entity:
public class TestEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String author;
#Column(insertable=false)
private String db_id;
}
And my test repository in which I try to create the query.
#Repository
#Transactional
public interface TestRepository extends JpaRepository<TestEntity, Long> {
#Query("INSERT INTO TestEntity VALUES (:object.id, :object.name :object.author)")
void insertSynchronizedColumns(TestEntity object);
}
This currently throws error:
antlr.MismatchedTokenException: expecting OPEN, found 'VALUES'
As a function argument I need the object and not the specific column names. Is there a way to retrieve object's id and other fields?
You can do it through nativeQuery as follows:
#Modifying
#Transactional
#Query("INSERT INTO TestEntity VALUES (:#{#object.id}, :#{#object.name}, :#{#object.author})",nativeQuery=true)
int insertSynchronizedColumns(#Param("object")TestEntity object);
Related
I have entity class User with composite key via #IdClass annotation
#Entity
#IdClass(UserId.class)
public class User {
#Id
private String name;
#Id
private String surname;
private boolean active;
}
Composite key:
#Data
public class UserId implements Serializable {
private String name;
private String surname;
}
I use Spring Data with hibernate JPA under hood. Therefore I have repo interface:
public interface UserRepo extends JpaRepository<User, UserId> {
}
And I'd like to get all active users from db by list of concrete names and surnames.
E.g. I'd like to use method like this
List<User> findAllByActiveTrue(List<UserId> ids);
How can I do query for this requirement via Spring Data or JPQL?
You can use #Embeddable & #EmbeddedId for composite primary key
#Embeddable
public class UserId implements Serializable {
private String name;
private String surname;
}
#Entity
public class User {
#EmbeddedId
private UserId userId;
...
}
Then query like
List<User> findByUserIdInAndActiveTrue(List<UserId> ids);
A good tutorial about #Embeddable & #EmbeddedId here
I know the title may sound a bit confusing, but I did not know how to summarize my problem on the title.
My main problem is that I do not want to return an specific column using PagingAndSortingRepository. Imagine the following scenario:
I have two entitys, one called Users:
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank()
#Column(name = "name")
private String name;
#Column(name = "password")
private String password;
}
And one called Cars:
#Entity
#Table(name = "car")
public class Car implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank()
#Column
private String name;
#ManyToOne(targetEntity = User.class, fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
#JoinColumn(name = "owner_id", referencedColumnName = "id")
private User owner;
}
I want to return a list of car by user's name using PagingAndSortingRepository. Using the following interface I can achieve that:
public interface CarRepository extends PagingAndSortingRepository<Car, Long> {
List<Car> findByOwner_name(String name);
}
However, with said interface the result will also return the user's password on it. I could use a for on each element of the list and set the password as null, but it would be troublesome in a scenario where there is a user with lots of cars. How could I make it so that the result of the list come with the specific column, password, without any value to the user?
Thanks in advance =).
ps: I thought about returning a list of projection instead of a list of Car, but I do not know how to say it to the projection that just one attribute from the class should be null.
You need to use Projections for this purpose. It is documented in detail here
Create an interface with fields you want to include in the entity to be returned.
For example, in your case it would be like this
interface CarSummary {
String getName();
Long getId();
UserSummary getUser();
interface UserSummary {
String getName();
Long getId();
}
}
and modify your repository like this
public interface CarRepository extends PagingAndSortingRepository<Car, Long> {
Collection<CarSummary> findByOwner_name(String name);
}
Projections can be used recursively. Something like this should work:
interface CarPojection{
Long getId();
String getName();
UserSummary getUser();
interface UserSummary {
Long getId();
String getName();
}
}
And your repository should return CarPojection
Find more information in Spring docs:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
You can return a subset of data by providing a matching constructor in your entity class.
#Query("select new com.foo.bar.entity.User(u.id, u.name) from User u where u.name = ?1")
List<User> findByOwner_name(String name);
In you class User just provide the constructor and other properties will be left null:
public User(Long id, String name) {
// ...
}
Overview
I've got an #Entity with an #EmbeddedId composite key. The entities are exposed over a REST api which uses a BackendIdConverter to convert the id string back to an instance of the #Embeddable composite key. My understanding is that this is then used to identify an instance of the #Entity, but that isn't happening.
Question
How is the #Embeddable composite key resolved back to an #Entity?
Code
#Entity
public class MyEntity {
#EmbeddedId
private MyEntityIdentifier id;
#Embeddable
public class MyEntityIdentifier implements Serializable {
public static final String COMPOSITE_KEY_DELIMITER = "_#_";
#Column
private String idPartOne;
#Column
#Temporal(TemporalType.DATE)
private Date idPartTwo;
#Component
public class StringToMyEntityIdentifierConverter implements BackendIdConverter {
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
String[] split = id.split(COMPOSITE_KEY_DELIMITER);
String idPartOne = split[0];
Date idPartTwo = Date.valueOf(split[1]);
return new MyEntityIdentifier(fullName, lastUpdated);
}
public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityIdentifier> {
}
I have superclass:
#MappedSuperclass
public abstract class BaseEntity {
#Id #GeneratedValue
private Long id;
#Version
private long version;
}
and two subclasses:
#Entity
#Table(name = "\"user\"")
public class User extends BaseEntity {
private String username;
#org.hibernate.annotations.Type(type = "yes_no")
private boolean isAdmin;
// constructor/getters/setters etc.
}
#Entity
public class Product extends BaseEntity {
public String name;
public BigDecimal price;
// constructor/getters/setters etc.
}
I can query for all subclasses using code:
entityManager.unwrap(Session.class)
.createCriteria(BaseEntity.class)
.list()
.forEach(x -> System.out.println(x));
how I can get the same results via JPA (without unwrap, is it possible?). I tried using createQuery("from BaseEntity") but get BaseEntity not mapped exception.
EDIT: I know that this will result in two SELECT statement. And it must be MappedSuperclass - I would like to not change that.
In hibernate, for example I have two object which has relation. The object is like this
First object : Customer
#Entity
#Table(name = "customer", catalog = "test")
public class Customer implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set<CustomerController> customerControllers = new HashSet<CustomerController>(0);
public Customer() {
}
//getter & setter
}
Second Object : CustomerController
#Entity
#Table(name = "customer_controller", catalog = "test")
public class CustomerController implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Customer customer;
//constructor, getter & setter
}
I want to select the customer_controller of certain customer. I get it by two manner. First manner :
#Override
public List<CustomerController> customerController(int customerId){
Customer customer = (Customer) sessionFactory.getCurrentSession().get(Customer.class, customerId);
return customer.getCustomerControllers()
}
Second manner :
return (List<CustomerController>)sessionFactory.getCurrentSession().createQuery("SELECT O FROM CustomerController O WHERE O.customerId=:CONDITION")
.setParameter("CONDITION", customerId)
.list();
Which manner is the most efficient one? Why?
Thank you.
To ensure it is easier to "turn on" show SQL parameter and monitor it.
I suppose in first hibernate able to generate two SQL query with entity mapping.
In second case should be generated only one select query.
In case when we use FetchType.EAGER think Hibernate will map Customer and CustomerController entity. Hope Hibernate fetch only CustomerController using HQL. To ensure you should monitor Hibernate behavior.