2

This is my entity:

@Entity
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "name")
private String name;

@Column(name = "surname")
private String surname;


@ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.MERGE)
@JoinColumn(name = "id_city")
private City city;
//...

}

In my Repository I have:

public interface UserRepository extends JpaRepository<User, Long>{

@Query("SELECT u FROM User u JOIN FETCH u.city")
public List<User> findAllUserForApi();

}

If there are any cities in table, findAllUserForApi() shows me full information about user:

[{"id":1,"name":"John","surname":"Pillman","city":{"id":1,"name":"New York"}]

If there are no cities, I want to get at least [{"id":1,"name":"John","surname":"Pillman","city":null] But I've got nothing: []

Help me please.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
Tom Wally
  • 542
  • 3
  • 8
  • 20

3 Answers3

5

Given that you are already using a custom query, the simplest solution would be a LEFT JOIN FETCH: @Query("SELECT u FROM User u LEFT JOIN FETCH u.city") This way all users will be loaded regardless of whether they have a city or not; and for those who have a city, it'll be available by user.getCity().

1

Why you write custom query here. You dont need.

Firstly you have to follow general convention:

@ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.MERGE)
@JoinColumn(name = "CITY_ID")
private City city;
...

And here JPA shows all information related with User.

public interface UserRepository extends JpaRepository<User, Long>{
    public List<User> findAll();
}
Arif Acar
  • 1,461
  • 2
  • 19
  • 33
  • 1
    Because I don't want to load all columns from my table. I have more than this ones. Also I have phones, address... And I don't want to see them in query answer. – Tom Wally Jun 28 '16 at 15:02
  • @TomWally if you dont want to see on your json you can user Jsonignore annotation. In this way you can show specific attributes. – Arif Acar Jun 28 '16 at 15:07
  • Yes, but JsonIgnore has no options. What If I want to show some fields like password for user with priority admin, but don't want to show for users with priority moderator. JsonIgnore doesn't give me a chance to show this fields to anyone. – Tom Wally Jun 28 '16 at 15:13
  • Maybe you can try extra DTO object and seperate attributes for each user title. if it doesn't see your business, when you return like password atrribute you can set them null. – Arif Acar Jun 28 '16 at 15:21
0

It looks like you are trying to use Lazy Loading with a predefined Query, I don't think this is going to work.

See, the JOIN FETCH in your query state the following:

Get all the Users which has u.City

So if you don't have a u.City for a user, the return would be empty.

More info on Join and Fetch

What you really want is the following:

public User findUserByID(Long userId)
{
    Session session = sessionFactory.getCurrentSession();  

    User user = (Users) session.createCriteria(User.class).add(Restrictions.idEq(userId)).uniqueResult();  

    // this will force SQL to execute the query that will join with the user's city and populate  
    //  the appropriate information into the user object.  
    Hibernate.initialize(user.geCity());  

    return user;  
}  

If the u.City is NULL, it will return a NULL. while the User object contains data.

Or in your case Find all users :

public List<User> findUserByID(Long userId)
{
    Session session = sessionFactory.getCurrentSession();  

    List<User> users = (List<User>) session.createCriteria(User.class);

    // this will force SQL to execute the query that will join with the user's city and populate  
    //  the appropriate information into the user object.  

    for (User user : users)
        Hibernate.initialize(user.geCity());  

    return user;  
}  

Note: I did not test the code, this is pseudo so you may want to change some of it.

source

Community
  • 1
  • 1
Igoranze
  • 1,506
  • 13
  • 35