spring data JPA OneToMany query pagination of child (many) table - spring-data-jpa

I have the following code. The number of rows in the One table will be about 100 and the number of rows in the Many table will be several hundred thousand (millions). I'm going to need to paginate the Many rows per single row in One when I query.
I'm not sure how to accomplish this.
My first thought is to get only the rows (and NOT the manyList content) in One but not even sure of that in JPA OneManyRepository. And then for each row use it's id primary key to query the Many with that one_id value and do pagination that way.
Any help will be apprecited.
Thanks,Jim
public interface OneManyRepository extends JpaRepository<One, Long> {
#Query(value = "select one.id,one.columnOne,one.columnTwo from one", nativeQuery = true)
Optional<List<One2>> findAllOne();
#Query(value = "select many.someTimeValue,many.value from many where many.one_id = :id", nativeQuery = true)
Optional<List<Many>> findAllBy(#Param("id") long id);
}
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class One2 {
private Long id;
private String columnOne;
private String columnTwo;
}
#Entity
#Table(name = "one")
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class One {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
private String columnOne;
private String columnTwo;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "one")
private List<Many> manyList;
}
#Entity
#Table(name = "many")
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Many {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
#ManyToOne
private One one;
private long someTimeValue;
#Column(length = 10)
private String value;
}

Related

Relation XX does not exist; could not extract Resultset error while using a view convertHibernateAccessException

I am using a view in my entity class. Although the view-column mappings are exactly the same as in entity class, I am receiving the exception "ERROR: relation "location_view" does not exist - Position: 15 - underlying exception is SQLGrammarException could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261)"
When I replace the view to the underlying SQL query, it works in SpringBoot. Can you please let me know where I am going wrong?
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Data
#ToString
#Entity
#Table(name = "location_view")
public class Location{
#Id
#Column(name = "id")
long id;
#Column(name = "name")
String name;
#Column(name = "total")
long total;
#Column(name = "created_by")
long createdBy;
#Column(name = "created_on")
Timestamp createdOn;
}
public interface LocationDAO extends JpaRepository<Location, Long> {
#Query(value = "select * from location_view", nativeQuery = true)
List<Location> getLocations();
}
In my controller, I am making call to locationDAO.getLocations();
Probably the table/view is in a different schema? Or maybe the user for the JDBC connection has no permission to read from that table/view?

Many To Many Relationship JPA with Entity

I have an issue trying to generate multiple relationship in JPA with three Entities.
Order
Product
Modifier
I have an Entity to handle the relationship many to many.
OrderProducts (order_id and product_id)
Contains the relationship of one order can have multiple products
OrderDetails (order_products_id and modifier_id)
Contains the id of the previous relationship Order-Products and the Id of the modifier which is a set of multiple values that can affect the price of the product.
Not quite sure how to handle this kind of relationship in JPA as I'm new to it.
You need a join entity with a composite key. You will need to research it further.
Your entities:
#Entity
#Table(name = "ordertable")
#Data
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "order")
#EqualsAndHashCode.Exclude
private Set<OrderProductModifier> products;
}
#Entity
#Table(name = "product")
#Data
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#EqualsAndHashCode.Exclude
private BigDecimal unitPrice;
}
#Entity
#Table(name = "modifier")
#Data
public class Modifier {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#EqualsAndHashCode.Exclude
private BigDecimal modifier;
}
And the entity that ties it all together will need to have the foreign keys for each of the above entities, as you have noted.
#Entity
#Table(name = "orderproductmodifier")
#Data
public class OrderProductModifier {
#EmbeddedId
private OrderProductModifierId id;
#MapsId("orderId")
#ManyToOne
#EqualsAndHashCode.Exclude
#ToString.Exclude
private Order order;
#MapsId("productId")
#ManyToOne
#EqualsAndHashCode.Exclude
private Product product;
#MapsId("modifierId")
#ManyToOne
#EqualsAndHashCode.Exclude
private Modifier modifier;
}
#SuppressWarnings("serial")
#Embeddable
#Data
public class OrderProductModifierId implements Serializable {
private Long orderId;
private Long productId;
private Long modifierId;
}
This is pretty simple to use:
private void run() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("UsersDB");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
Product product = new Product();
product.setUnitPrice(BigDecimal.TEN);
em.persist(product);
Modifier modifier = new Modifier();
modifier.setModifier(new BigDecimal(".90"));
em.persist(modifier);
Order order = new Order();
em.persist(order);
OrderProductModifier opm = new OrderProductModifier();
opm.setId(new OrderProductModifierId());
opm.setOrder(order);
opm.setProduct(product);
opm.setModifier(modifier);
em.persist(opm);
em.getTransaction().commit();
em.clear();
Order o = em.createQuery("select o from Order o join fetch o.products where o.id = 1", Order.class).getSingleResult();
System.out.println("Order for " + o.getProducts());
System.out.println("Order cost " + o.getProducts().stream().map(p->p.getProduct().getUnitPrice().multiply(p.getModifier().getModifier()).doubleValue()).collect(Collectors.summingDouble(Double::doubleValue)));
}
The above query could be better, but that will give you something to work on.

Hibernate #OneToMany where discriminatorValue = 'SOMETHING'

Table pdp_billable_field_state carries configuration for various fields.
Owner of configuration can be any number of Entity`s
This configuration is same for each entity that matches the #DiscriminatorValue
#Getter
#Setter
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "entity_type")
#Table(name = "pdp_billable_field_state")
public abstract class EntityFieldStateJpa extends AuditableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "status_id")
private StatusJpa status;
#Column(name = "field", columnDefinition= "varchar(255)")
private String field;
private boolean disabled;
private boolean hidden;
}
#DiscriminatorValue("PURCHASE")
public class PurchaseEntityFieldStateJpa extends EntityFieldStateJpa {}
#Getter
#Setter
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "pdp_purchase")
public class PurchaseJpa {
// omitted
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
// i do not have a join_column since all records with entity_type PURCHASE map to all purchases, as these are configurations used by all purchases. Should i try and introduce #JoinTable maybe?
#Where(clause = "entity_type='PURCHASE'")
private List<PurchaseEntityFieldStateJpa> fieldStates;
}

Query for joins in Spring JPA

I have the below entities
#Entity
#Getter
#Setter
public class Aggregate {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "aggregate")
private Set<Single> singleSet;
}
#Entity
#Getter
#Setter
public class Single {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
private Integer number;
#ManyToOne
#JoinColumn(name = "agg_id")
private Aggregate aggregate;
}
I also have the below repository
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
}
I want to return all associated Single records where number in object Single is equal to some random number
I am assuming that the query will be something like this
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
public List<Single> findBySingleSet_Number(Integer number);
}
However when I try to use Intellij to complete my named query it always populates like this
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
public List<Single> findBySingleSet_Empty_Number(Integer number);
}
I am wondering what the Empty stands for ?
Also should I create another Single repository since the query is related to returning Single records.

JPA two Entities one Relationship: How do I obtain a Set of an entity that is linked through a relationship?

I have three tables each mapping to one of these entities. The 'assigned' table acts as the relationship between 'users' and 'roles' with a foreign key to each table. How would I map this on my entities so that I can get a Set of EntityRoles from the UserEntity? I can't quite figure out how to make this work. Is this even possible?
#Entity
#Table(name = "users")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="user_id")
private long id;
#Column(name="user_username")
private String username;
#Column(name="user_password")
private String password;
#Column(name="user_email")
private String email;
//I want to be able to get a set of RoleEntities
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id")
private Set<RoleEntity> roles;
}
#Entity
#Table(name = "assigned")
public class AssignedEntity implements Serializable {
#Id
//#Column(name = "assigned_role")
#ManyToOne(targetEntity = RoleEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_role")
private long roleId;
#Id
//#Column(name = "assigned_user")
#ManyToOne(targetEntity = UserEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_user")
private long userId;
}
#Entity
#Table(name = "roles")
public class RoleEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
#OneToOne(fetch = FetchType.LAZY, mappedBy="roleId")
private long id;
#Column(name="role_name")
private String name;
}
You are using an incorrect/inconvenient mapping. Always keep things as simply as possible.
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
}
#Entity
#Table(name = "roles")
public class Role {
#Id
private Long id;
#Column
private String name;
}
A persistent provider will create a (valid) join table for you. You can specify the name of the join table using #JoinTable annotation. Also you will need to think about auto generation values of id for the Role entity: the roles table is something like a reference data table. So, probably, you will need to hardcode the id values.
To get user roles (in the persistent context):
user.getRoles()