How to make a field as optional in a JPA Entity? - java

I have Table User in SQL Server DB with close to 30 columns. I have also created an JPA Entity for corresponding DB Table.
The JPA entity looks something like this:
#Entity
#Table(name="USER")
#Setter
#Getter
public class User{
#Id
#Column(name="ID",nullable=false)
private Integer id;
#Column(name="NAME")
private String name;
#Column(name="ADDRESS")
private String address;
#Column(name="FATHER_NAME")
private String fathersName;
}
Now I am trying to create a native query which will only fetch id and name from the User Table.
The Repository class looks something like this.
#Repository
public interface UserDao extends JpaRepository<User,Integer>{
#Query(value=" SELECT u.ID,u.NAME from USER u", nativeQuery=true)
List<User> fetchUser();
}
Now when this is being executed, it is throwing an exception as below:
com.microsoft.sqlserver.jdbc.SqlServerException: The column name address is not valid
When I add the address column to my query this exception goes but then it come for another field.
com.microsoft.sqlserver.jdbc.SqlServerException: The column name father_name is not valid
So, now I want to modify the JPA Entity in such a way that this fields became optional.
I have tried using
#Transient but if some other query is using this address field then it will come as null over there.
I have also tried all the below annotations:
#Basic
#NotFound(action=NotFoundAction.IGNORE)
#Column(nullable="true")
#JsonProperty
But none of this annotations work for me.

You can define additional constructor for the User entity:
#Entity
#Table(name="USER")
public class User {
public User(){
}
public User(Integer id, String name){
this.id = id;
this.name = name;
}
// ...
}
and then write the following query:
#Query("select new your.package.User(u.id, u.name) from User u")
List<User> fetchUser();
Note that this is not native, but jpql query.
Please also note that according to the hibernate documentation:
The projection class must be fully qualified in the entity query, and it must define a matching constructor.
The class here need not be mapped. It can be a DTO class.
If it does represent an entity, the resulting instances are returned in the NEW state (not managed!).
EDIT
You can also try to use spring data jpa projections in the following way:
Define an interface:
interface UserIdWithName {
Integer getId();
String getName();
}
The important thing here is that the properties defined here exactly match properties in the aggregate entity.
Use this interface in the query method:
#Query("select u from User u")
List<UserIdWithName> fetchUserIdWithName();
The query execution engine creates proxy instances of that interface at runtime for each element returned and forwards calls to the exposed methods to the target object. Please note that you can not select only some fields in the query here.

You can use
#Query(value=" SELECT u.ID,u.NAME, '' as address, '' as father_name from USER u", nativeQuery=true)
List<User> fetchUser();
It will set those fields to empty string.

I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Integer getId();
String getName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<UserDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Related

Spring Data for Postgresql specific query - DELETE RETURNING with Spring repositories

My question is very concrete and I could not find any answers on Stackoverflow or wider internet.
I would like to use Spring repository to execute "DELETE FROM TABLE ... RETURNING *" type of query, which is specific to Postgresql.
Assume that I have following classes:
#Entity
#Getter // lombok annotations
#Setter
public class Item {
#Id
#GeneratedValue
private Integer id;
private String name;
}
then I would like to have something like following:
interface ItemRepository extends CrudRepository<Item, Integer> {
// This is a Postgres specific query
#Query("SELECT FROM Item where Item.id=?1 RETURNING *")
Optional<Item> deleteByIdReturning(Integer id)
}
How can I do something like this?
Additional info:
In order to motivate my needs a bit better I would like to have a CRUD-y REST resource, which will return 200 HTTP status code together with deleted resource if something has been deleted, but will return HTTP status code 204 without body in case that nothing has actually been deleted on the server side.
I thank you in advance for your time
If you are using Spring Data JPA you can try using native query this way:
#Query("SELECT FROM Item where Item.id=?1 RETURNING *", nativeQuery = true)
Optional<Item> deleteByIdReturning(Integer id)

JPA Projection #OneToMany not working 'Unable to locate appropriate constructor'

I have a large entity-class with many, many fields and a projection-class which should be a part of the large one.
Everything works fine, except the #OneToMany field. The #OneToMany field should be a list of addresses, but when converting it to the projection-class I always get the error "Unable to locate appropriate constructor [...] Expected arguments are: long, [...], ***.entity.Address".
The converter is searching for a single address Object instead of a List of Address Objects, and I don't understand why. I use lombok #Data and #AllArgsConstructor, so Getter and Setter should be there.
#Entity
#Data
public class House implements Serializable {
#Id
#Column(name = "ID", precision = 5)
private Long id;
#OneToMany
#JoinColumn(name = "HouseID")
private List<Address> identAdressen;
}
/// ----------------
#Data
#AllArgsConstructor
public class HouseView {
private Long objnr;
private List<Address> identAdressen;
}
When I remove the "List" in the HouseView-class it works as long as there are only single addresses, but when there are multiple it crashes too.
I don't get it why he tries to find a HouseView-Constructor with an single address-object, when in both classes there are Lists of Addresses.
Let trying not using lombok and see if it works
Spring Data Projections do not support collections but I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(House.class)
public interface HouseView {
#IdMapping
Long getObjnr();
Set<AddressView> getIdentAddressen();
#EntityView(Address.class)
interface AddressView {
#IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
HouseView a = entityViewManager.find(entityManager, HouseView.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<HouseView> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
What you can do is to write custom query on HouseRepository as
#Query("SELECT new com.packagename.HouseView(hos) from House hos")
then house view class can be as follows
public class HouseView {
private Long objnr;
private List<Address> identAdressen;
public HouseView(House house) {
identAdressen = house.identAdressen;
}
}
Hope it will work :) You can add more fields into constructor from join tables if required. It might help others coming late on post.

Converting an #Entity to a projection interface manually

So I've been using Spring Data Repositories most of the time. But I've reached a use-case where I cannot use my Spring Repository to retrieve the entity that I need to return to the client.
So I have my class ResourceEntity which is a Spring Data Entity. And I'd like to return this entity as a ResourceProjectioninterface.
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
private String anotherFieldThatIsNotInTheProjection;
}
public interface ResourceProjection {
Long getId();
String getName();
}
Usually with a Spring Repository, I'd define something like that :
public interface ResourceRepository extends PagingAndSortingRepository<ResourceEntity, Long> {
Optional<ResourceProjection> getById(Long id);
}
In this case I can't use the "automatic proxy" generated by Spring Data to automatically implement my projection with the entity's data.
So my question is : Is there a way to "manually" convert the entity to the projection ?
Another solution I thought of is returning the entity and using Jackson annotations like #JsonIgnore to prevent some of my data to be returned, but that is not optimal with the way my code was written.
Otherwise I can always create a DTO class that will fill up with the data from the Entity. But as I have already created my projection for other purposes, I would like avoid creating a second "DTO".
You can do the projection programmatically in this way:
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
//...
resourceEntity = //find resource
ProjectionFactory pf = new SpelAwareProxyProjectionFactory();
ResourceProjection rp = pf.createProjection(ResourceProjection.class, resourceEntity)
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
A mapping for your model could look as simple as the following
#EntityView(ResourceEntity.class)
interface ResourceProjection {
#IdMapping
Long getId();
String getName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ResourceProjection dto = entityViewManager.find(entityManager, ResourceProjection.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Implementing interface projection using native sql query
1. OurResourceEntity.java class
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
}
2. Creating projection Interface name ProjectedResource.java, which maps data collected by the SQL query from repository layer method
public interface ProjectedResource {
Long getId();
String getName();
String getAnotherProperty();
}
3. Creating Repository layer method: getProjectedResources()
We are considering the database table name is resource.
We are only fetching id and name here.But using interface projection we can change the properties name according to our desire.
#Query(name="select id, name, anotherProperty from resource", nativeQuery=true)
List<ProjectedResource> getProjectedResources();
Hope the issue will be resolved!

How to prevent Spring JPA Entities from becoming optional when saving to CRUDRepository?

I was trying to learn Spring Framework and ran into a problem with saving entities into CRUD Repository. I had few Entities with automatic numeric ID generation and they work just fine, but then I tried to make a class with String being a primary key just like this:
#Entity
#Table(name = "USERS")
#Builder
public class User {
#Id
#Column(name = "USER_NAME", nullable = false)
#Getter #Setter
private String name;
#Column(name = "USER_PASS", nullable = false)
#Getter #Setter
private String pass;
}
First I was getting exceptions about this class not having a default constructor:
org.springframework.orm.jpa.JpaSystemException: No default constructor for entity: : com.company.Model.User; nested exception is org.hibernate.InstantiationException: No default constructor for entity: : com.company.Model.User
Already weird, but still I decided to change #Builder annotation into 2 constructors, one with both arguments and second with none. I tried to save the entity instance into CRUD Repository userDAO (which is nothing more than interface extending CRUDRepository) by the typical test:
User admin = new User("admin", "6aDcZ72k");
...
#Test
public void saveUserAndFindById() {
admin = userDAO.save(admin);
assertThat(userDAO.findById(admin.getName())).isEqualTo(admin);
}
The result was assertion failed because the saved entity had "Optional" type:
org.junit.ComparisonFailure:
Expected :com.company.Model.User#2c06b113
Actual :Optional[com.company.Model.User#2c06b113]
I know I'm doing something really wrong but can't figure this out. Or maybe there is a way to just prevent making it optional? There must be few other entities with the reference on this class, but these references obviously don't work because of the above issue.
First of all,jpa require the entity has a No Arguments Constructor cause it will create a instance first and then populate it.The easiest way is to add #NoArgumentsConstructor that offered by lombok on the entity class.
And then,Optional is used by spring data jpa in order to avoid NullPointException and in fact it be is useful actually.If you want to use the interface that Spring-data-jpa offered,then you have to use Optional too.You cloud look here for more info about Optional:link1,link2
By the way,I usually use it like:
ExampleEntity example=exampleRepository.findById(id).orElseThrow(()->new ExampleNotFoundException());
In this way,you dont need to deal with Optional or think about NullPointException.
or:
ExampleEntity example=exampleRepository.findById(id).orElse(null);
In this way if you cant find the target entity,then it will be null.So dont forget to check if the entity is null.
Hope it could help~~~
It is not your save(...) that is returning Optional but userDAO.findById(admin.getName(). According to the documentation, CrudReposiotry provides a findById() whose return type is Optional<T>.
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
Optional<T> findById(ID primaryKey);
}
If you do not want Optional as return type, You will need to provide your own method to do that. For example:
public interface PeronRepository extends CrudRepository<Person, String> {
Person findById(String personId);
}

JPA - how to model this join with conditions?

I was trying to find an answer but, unfortunately, with no luck.
The data structure looks like this:
TABLE_X - contains userId, also userType telling if this is external or internal user
INTERNAL_USERS - contains key userId
EXTERNAL_USERS - also contains key userId
TABLE_X.userId is either INTERNAL_USERS.userId or EXTERNAL_USERS.userId.
Now, I would like to map an entity out of TABLE_X and have user object mapped to correct entity, either INTERNAL_USERS or EXTERNAL_USERS.
How should I do this?
Should I create two fields and map one to INTERNAL_USERS and one two EXTERNAL_USERS and just see which one is not empty?
If I understand correctly your question, what you have to do is to replicate structure of the TABLE_X columns with fields on the TABLE_X class, and add to fields one for INTERNAL_USERS.userID and one for EXTERNAL_USERS.userID
But if you store on TABLE_X.userType if a user is internal or external, I think that the best thing you can do is not create any other table, because you just have the information you need on your first table (TABLE_X). If you want to know all the users that are internal for instance, just do a SQL and select all the values from TABLE_X where userType = "Internal"
Use Hibernate inheritance. Check out the Table per class inheritance pattern. Here you have both INTERNAL_USERS or EXTERNAL_USERS data in TABLE_X with userType as the discriminator column.
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1191
Given the table structure, you can use JPA Inheritance as detailed here:
https://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Example_joined_inheritance_annotations
In Hibernate you can model such relationships as follows. When querying for a User you can then rely on Hibernate to return an instance of the correct type.
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public class User{
#Id
private Long userId;
}
#Entity
public class InternalUser extends User{
}
#Entity
public class ExternalUser extends User{
}
As noted in the article linked to, Hibernate does not require a discriminator column to be specified when using joined inheritance. It does however support a discriminator column if one is available. As you have one available in your schema - userType - then you could explicitly specify it if you wish. I imagine this would yield some performance benefit in terms of the generated SQL:
Mappings with optional discriminator column:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="userType")
public class User{
#Id
private Long userId;
}
#Entity
#DiscriminatorValue("INT")
public class InternalUser extends User{
}
#Entity
#DiscriminatorValue("EXT")
public class ExternalUser extends User{
}

Categories

Resources