Home > Software design >  Spring data one-to-many select query
Spring data one-to-many select query

Time:04-27

I'm trying to configure out hql for many-to-one relationship and facing next issue: spring data doesn't select restaurant if votes count for today is less than 1. In database everything's ok

Result should be

  {
    "id": 3,
    "name": "Kroger",
    "votes": 2
  },
  {
    "id": 2,
    "name": "Fridays",
    "votes": 1
  },
  {
    "id": 4,
    "name": "Wingstop",
    "votes": 1
  },
  {
    "id": 1,
    "name": "Macdonalds",
    "votes": 0
  }

But it is

  {
    "id": 3,
    "name": "Kroger",
    "votes": 2
  },
  {
    "id": 2,
    "name": "Fridays",
    "votes": 1
  },
  {
    "id": 4,
    "name": "Wingstop",
    "votes": 1
  }

Restaurant entity

@Entity
@NoArgsConstructor
@Getter
@Setter
@Table(name = "restaurant", uniqueConstraints = @UniqueConstraint(columnNames = "name"))
public class Restaurant extends NamedEntity {
    @OneToMany(mappedBy = "restaurant", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JsonManagedReference
    private Set<Vote> votes;

    public Restaurant(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

Vote entity

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "votes", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "date"}, name = "unique_user_id_per_date_idx")})
public class Vote extends BaseEntity {
    @Column(name = "date")
    @CreationTimestamp
    private LocalDate date;

    @ManyToOne
    @JoinColumn(name = "user_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private User user;

    @ManyToOne
    @JoinColumn(name = "restaurant_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Restaurant restaurant;

    public Vote(Integer id, LocalDate date, User user, Restaurant restaurant) {
        super(id);
        this.date = date;
        this.user = user;
        this.restaurant = restaurant;
    }
}

Restaurant repository

@Transactional(readOnly = true)
public interface RestaurantRepository extends BaseRepository<Restaurant> {

//    @Query("select r from Restaurant r join r.votes v where v.date=current_date")
//    @Query("from Restaurant r left join  r.votes v where v.date=current_date")
//    @Query("select r from Restaurant r join fetch Vote v on v.date=current_date")
//    Set<Restaurant> findAllForCurrentDate();

//    @Query("from Restaurant r left join fetch r.votes as v on v.date=current_date")

    @Query("from Restaurant r left outer join fetch r.votes as v where v.date=current_date")
    Set<Restaurant> findAllForCurrentDate();
}

If you need additional info please let me know.

CodePudding user response:

Problem is solved. Solution:

@Entity
@NoArgsConstructor
@Getter
@Setter
@AllArgsConstructor
@Table(name = "restaurant", uniqueConstraints = @UniqueConstraint(columnNames = "name"))
@NamedEntityGraph(name = "graph.Parent.children", attributeNodes = @NamedAttributeNode("votes")) // added this
public class Restaurant extends NamedEntity implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    @OneToMany(mappedBy = "restaurant",
            fetch = FetchType.EAGER,
            cascade = CascadeType.ALL)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JsonManagedReference
    private Set<Vote> votes = new HashSet<>();

    public Restaurant(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

And repo's method

@Query("select distinct r from Restaurant r left join r.votes v on v.date=current_date")
    @EntityGraph(value = "graph.Parent.children") // added this
    Set<Restaurant> findAllForCurrentDate();
  • Related