Dynamic Filter, Hibernate - filter

I have this entity model. I would like to filter the mapped association Client-Product with a parameter "ISIN";
I've tried:
#FilterDef(name="filterIsin", parameters ={#ParamDef(name="insinList" ,type ="string")})
#Filter(name="filterIsin", condition = "ISIN in (:insinList))
...
Filter filter = entityManager.unwrap(Session.class).enableFilter("filterIsin");
filter.setParameterList("insinList, ...");
But I don't get the filtered collection. As you can see the relation is Lazy, when I get the data with Hibernate.initizlize() the collection is not filtered.
in which entity do i need to define the filter?
Is there any problem with Lazy?
Client
...
#OneToMany(fetch=FetchType.LAZY)
#Fetch(FetchMode.SUBSELECT)
#JoinColumns(...)
private List<PiProduct> products;
PiProduct
...
#ManyToOne
#JoinColumns(...)
private Product product;
Product
...
#Column(name=ISIN)
private String isin;
#OneToMany(mappedBy = "productos")
private List<PiProduct> piProducts;
...
The collection of clients with the products filtered by isin

Related

Spring does not persist bi-directional OneToOne relation on owning side

In my spring boot project I have a Document class that has a bi-directional OneToOne relationship to an Invoice class, which share the same ID.
Document
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Invoice invoice;
Invoice
public class Invoice {
#Id
#Column(name = "document_id")
private Long documentId;
#OneToOne(mappedBy = "invoice")
#MapsId
#JoinColumn(name = "document_id")
private Document document;
The document entity is created prior to the invoice entity. Later on I create an invoice entity via a MapStruct DTO-Mapping. I then save the entity to "generate" the document_id value.
After saving the invoice entity, I assign the invoice entity to the document entity and save the document entity via the repository. However, the relation to the invoice entity is not persisted in the database.
The invoice entity persists as should be with the corresponding document_id as primary key.
Service code
Invoice newInvoice = invoiceMapper.fromDto(dto);
newInvoice = invoiceRepository.save(newInvoice);
document.setInvoice(newInvoice);
documentRepository.save(document);
InvoiceMapper
#Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, uses = {DocumentService.class})
public interface InvoiceMapper {
#BeanMapping(ignoreByDefault=true)
#Mapping(source = "document", target = "document")
Invoice fromDto(Dto dto);
Previously, I tried mapping the document_id in the MapStruct mapper aswell, but then I received an "attempted to assign id from null one-to-one property" exception on save (even though document and document_id were correctly defined).
When debuggin the code, it correctly shows that the invoice entity was set on the document entity, but unfortunately it is not persisted in the database.
Curiously, I am almost certain that at some point in the coding process it did work as intended. But I can not figure out where the issue is. Help would be much appreciated.
This is not setup correctly as you have not specified anything to set the Invoice's document_id column - you'd have to set this yourself from the documentId long. You must pick one side to have a foreign key to the other - presumably the Invoice has the foreign key to Document and is going to use that as its primary key as well. If that is the case, this needs to be:
public class Invoice {
#Id
#Column(name = "document_id")
private Long documentId;
#OneToOne //this is the owning side of the relationship!
#MapsId
#JoinColumn(name = "document_id")
private Document document;
..
}
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(mappedBy = "document")
private Invoice invoice;
..
}
MappedBy indicates that the other side controls setting the foreign key values. Note though that your Invoice will not have a documentId value set, and that you do not need to manually set it. The MapsId annotation tells JPA to pull the value from the Document ID when it is generated and to use that for the document_id column, and will set the documentId Long at the same time.
This then will allow you to create a new Document and Invoice and just call save on the document - once. It isn't enough to just add an invoice to the document - the ID within Invoice is entirely controlled by the Invoice.document reference, so if it isn't set, it will be left null. You must maintain both sides of bidirectional relationships yourself to have the model in synch with what you want in the database. Or at least set the owning side of any bidirectional relationship.

Integrity Constraints violation error when deleting record in Spring boot

I am new into Spring Boot framework, I want to implement an Entity Relationships so to achieve the following cases:
Consider the following example Entities Relationships
#Entity
class Category {
private Long id;
private String name
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private List<Product> products = new ArrayList<>();
}
#Entity
class Product {
private Long id;
private String name
#ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.DETACH)
private Category category;
}
I use the below approach to delete objects with Jpa Repository API
Product product = productRepository.getOne(productId);
productRepository.delete(product);
Category category = categoryRepository.getOne(categoryId);
categoryRepository.delete(category);
Based on the above relationships I want to be able to:
When deleting Category record, delete all related Products.
When deleting Product record, detach from the Category's products
I am aware of the cascade types but when deleting Category record I get constraints violation i.e. category x is still referenced into another table i.e. Products.

Filter ChildEntites in jpa specifiction

I am using JPA specs for searching of orders but inside my order Entity there is an another property ProductEntity which is a list. there is a another property ProductType inside my ProductEntity. now i need to filter my productList inside my orderEntity on the basis of productType That i will send in RequestParam of my api..
1.here is my parent Entity
OrderEntity{
private String tgxId;
private List<ProductEntity> products;
}
2.here is my ChildEntity
ProductEntity{
private String id;
private String orderId;
ProductType type;
}
now , when i do search orderslist i also need to filter my product list in the basis of ProductType that i send from RequestParam.
Result should contains entire order object list but products list inside each orderEntity should be filtered on the basis productType that i will send form RequestParam.
Thanks.

Join 2 tables using Spring JPA

I have two entities(Invoice and InvoiceItems) without adding any relationship.
Invoice
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long invoiceID;
#Column(name="code")
private String code;
//other columns
}
Invoice Items
public class InvoiceItems {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long invItemID;
#Column(name="invoice_id")
private Integer invoiceId;
//other columns
}
Can I join these entities and get data without adding relationship using JPA?
If it isn't possible how to join 2 entities using JPQL or Native query?
If your data is valid then using native query you can do that
#Query(nativeQuery = true, "select * from Invoice i join InvoiceItems im on i.id = im.invoice_id")
public List<Invoice> findData();
But that is not a good way join without relation using JPA.
Yes, you can join these entities and get data without adding relationship using JPA, but it's a little bit losing the purpose of using JPA.
You need to create a java class first, which will be the returning data object from the DB. After that you can use entityManager's createNamedQuery method to get the result.
createNamedQuery(String sqlString, ResultClass.Class)
sqlString may be something like:
SELECT INV.INVOICE_ID
INV.CODE
INV_ITEMS.INV_ITEM_ID
FROM INVOICE INV
JOIN INVOICE_ITEMS INV_ITEMS
ON INV.INVOICE_ID = INV_ITEMS.INVOICE_ID;
And the corresponding ResultClass:
public class ResultClass {
private Long invoiceID;
private String code;
private Long invItemID;
// other columns
}
Or you can even use RowMapper to map the object all by yourself for more flexibility by using JdbcTemplate with query() method.

Fetch child entities when finding by a normal field in Spring Data JPA

I am using Spring Data JpaRepository to find List of entities matching a particular field. Consider the following code snippet:
Entity:
#Entity
#Table(name = "master")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Master implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "id", nullable = false)
private Long Id;
#NotNull
#Column(name = "user_id", nullable = false)
private String userId;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="id", referencedColumnName="id", insertable=false, updatable=false)
private Details Details;
Spring Data Custom JpaRepository:
public interface MasterRepository extends JpaRepository<Master,Long> {
List<Master> findMasterByUserId(String userId);
}
When i am using findBookingMasterByUserId repository method to find all records with specific user id, I am getting the List of Master entity but I am not getting the Details entity that has id as foreign key in it.
However, I get all the dependent entities when I use out of the box findAll method of JpaRepository but with custom findMasterByUserId repository method, child entities are not being fetched eagerly.
Any type of help would be highly appreciated. Thanks!
You can use #EntityGraph in your repo to eagerly get associated data:
#EntityGraph(attributePaths = {"details"})
List<Master> findBookingMasterByUserId(String userId);
P.S. Don't forget to change 'Details' field to details;
Your entity name is "Master" not "booking_master".
Change your method to:
List<Master> findByUserId(String userId);
Refer to below spring docs for more information on query creation mechanism for JPA.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Alternatively,
#Query("SELECT m FROM Master m WHERE m.userId = :userId")
List<Master> findByUserId(#Param("userId") String userId);
The query generation from the method name is a query generation strategy where the invoked query is derived from the name of the query method.
We can create query methods that use this strategy by following these rules:
The name of our query method must start with one of the following
prefixes: find…By, read…By, query…By, count…By, and get…By.
If we want to limit the number of returned query results, we can add
the First or the Top keyword before the first By word. If we want to
get more than one result, we have to append the optional numeric
value to the First and the Top keywords. For example, findTopBy,
findTop1By, findFirstBy, and findFirst1By all return the first entity
that matches with the specified search criteria.
If we want to select unique results, we have to add the Distinct
keyword before the first By word. For example, findTitleDistinctBy or
findDistinctTitleBy means that we want to select all unique titles
that are found from the database.
We must add the search criteria of our query method after the first
By word. We can specify the search criteria by combining property
expressions with the supported keywords.
If our query method specifies x search conditions, we must add x
method parameters to it. In other words, the number of method
parameters must be equal than the number of search conditions. Also,
the method parameters must be given in the same order than the search
conditions.

Resources