I'm using Spring Data 1.13 and spring-boot-starter-data-jpa-1.5.4. (can't upgrade)
I need to fetch only few fields in nested entities and i have a multiple optional search criteria...
public class Entity1 {
private Entity2 e2; --> i need e2.innerEntity.field
private Entity3 e3; --> i need e3.innerEntity2.field...
.... other entity and fields...
}
fetching 950 Entity1 is a very slow task due to Eager Fetching on nested entity...
I've tried with Specification, but I can't do projection (or I am not able...)
what can i do? :( thanks for your attention... and i'm sorry for my English.
Related
I have an basic spring application that uses hibernate and mapstruct
There are two Entities, each are implemented to have their subchild entities as List attribute in a ManyToMany relation
So there is
EntityA.class
with List<EntityB> (fetchType Lazy)
and vice versa
Now when my client calls, it wants to get a DTO that represents like following:
EntityADTO
with List<Long> entityBIds
How can I get my EntityA with only the Ids of EntityB most efficient and without loading the complete EntityB and post process it after?
Thanks a lot!
The #ManyToMany association information is persisted in a dedicated (join-)table and is loaded lazily on collection access, so there needs to be another query.
Instead of querying for the complete information of all associated entities, you could specifically query only for the needed id property.
Possible queries could look e.g. like this:
// Spring-Data repository (requires an extra interface for the result):
interface IdOnly(){
Long getId();
}
interface EntityBRepository extends JpaRepository<EntityB, Long> {
List<IdOnly> getIdByEntityAId(Long enitityAId);
}
// alternative JPQL query (does not need the interface):
#Query("SELECT b.id FROM EntityB b JOIN b.entityAs as a WHERE a.id=:entityAId")
List<Long> getIdByEntityAIdJpaQuery(#Param("enitityAId") Long enitityAId);
This way, only the needed EntityB ids for an associated EntityA are loaded from the DB.
For even further tuning, one could also write a native query directly accessing only the join-table, which avoids all joins:
#Query(nativeQuery = true, //
value = "SELECT entityBId FROM entityA_entityB WHERE enitityAId=:enitityAId")
List<Long> getIdByEntityAIdNative(#Param("enitityAId") Long enitityAId);
For executing the query when mapping with mapstruct, you can use the spring repository bean e.g. as described here: https://stackoverflow.com/a/51292920
In addition to #Fladdimir's answer which is a great approach if you only need the list of values occasionally, JPA allows defining Entity Graphs that can specify what in an object graph you want loaded. This can allow you to define your entity and specific attributes from child/referenced entities in the graph, allowing objects to be returned but the bulk of the data unfetched. This can allow you to process Entity B instances, but without them being fully populated.
There are many tutorials but I've referenced https://www.baeldung.com/jpa-entity-graph more than once. As the tutorial referenced mentions though, Hibernate might have some issues with how it handles attributes that are normally eagerly fetched, so it might not work the way you want (but will with other JPA providers like EclipseLink, which is where I've used this).
Alternatively, if this is a collection of IDs you are going to want/need frequently, you can modify your object model to have them fetched differently.
public class EntityA {
..
#ElementCollection
#CollectionTable(name = "RELATION_TABLE_NAME", joinColumns = #JoinColumn(name = "A_ID", insertable=false, updatable=false))
#Column(name = "B_ID", insertable=false, updatable=false)
List<Long> bIds;
}
This allows fetching the foriegn keys automatically in your AEntity. I've made it read-only, assuming you'd keep the existing A->B relationship and use that to set things. Doing so though means that these two relationships are entirely separate, and so might result in different queries to fetch this same set of data.
If that is a concern, you can alter things again, and remove the existing A->B relationship, and stick it in an intermediary object AB.
public class EntityA {
..
#ElementCollection
#CollectionTable(name = "RELATION_TABLE_NAME", joinColumns = #JoinColumn(name = "A_ID"))
List<AB> listOfBs;
}
#Embeddable
public class AB {
#Column("B_ID", insertable=false, updatable=false)
Long bId;
#ManyToOne(fetch=LAZY)
#JoinColumn(name = "B_ID")
B b;
}
This would allow you to fetch As and use B's ID values without having to fetch from the B table. Note that I've marked the basic bId property as read-only, assuming that your existing app would be setting things by assigning a B reference to the relationship, but you could mark the relationship as read-only instead, and set the FK value using the bId. This might be more efficient long term, as you don't have to look up the B instance to set the relationship.
Alternatively again, you can make AB an entity instead of an embeddable, and allow it to exist and be queried upon outside of As and Bs. There are quite a few options though, and ways to map it, and not likely necessary for a simple model and use case.
I recently asked this question : Spring Mongodb - Insert Nested document?
And found out that Spring-Data-MongoDB does not support such behavior - so now I need a working alternative.
Now - to avoid having you look at the code on another page, I am going to paste it here from the other question... Here are my two POJOs :
#Document
public class PersonWrapper {
#Id
private ObjectId _Id;
#DBRef
private Person leader;
#DBRef
List<Person> delegates;
// Getters and setters removed for brevity.
}
public class Person
{
#Id
private ObjectId _Id;
private String name;
// Getters and setters removed for brevity.
}
Now, what I want to be able to do here - is send up a JSON object in my POST request as follows :
{
"personWrapper":
{
"_Id":"<ID HERE (MIGHT WANT SQL TO GENERATE THIS DURING CREATE>",
"leader":{
"_Id":"<ID HERE (MIGHT WANT SQL TO GENERATE THIS DURING CREATE>",
"name":"Leader McLeaderFace"
},
delegates:[{...},{...},{...}]
}
}
At this point - I would like the SQL side of this to create the individual records needed - and then insert the PersonWrapper record, with all of the right foreign keys to the desired records, in the most efficient way possible.
To be honest, if one of you thinks I am wrong about the Spring-Data-MongoDB approach to this, I would still be interested in the answer - because it would save me the hassle of migrating my database setup. So I will still tag the spring-data-mongodb community here, too.
If I understand well you want to cascade the save of your objects ?
ex : you save a PersonWrapper with some Person in the delegates property and spring data will save PersonneWrapper in a collection and save also the list of Person in another Collection.
It is possible to do that with Spring DATA JPA if you annotate your POJO with the JPA annotation #OneToMany and setup cascade property of this annotation. See this post
However the cascade feature is not available for Spring DATA mongoDB. See documentation .First you have to save the list of Person and then you save PersonWrapper.
Is it possible to publish two different repositories for the same JPA entity with Spring Data Rest?
I gave the two repositories different paths and rel-names, but only one of the two is available as REST endpoint.
The point why I'm having two repositories is, that one of them is an excerpt, showing only the basic fields of an entity.
The terrible part is not only that you can only have 1 spring data rest repository (#RepositoryRestResource) per Entity but also that if you have a regular JPA #Repository (like CrudRepository or PagingAndSorting) it will also interact with the spring data rest one (as the key in the map is the Entity itself).
Lost quite a few hours debugging random load of one or the other. I guess that if this is a hard limitation of spring data rest at least an Exception could be thrown if the key of the map is already there when trying to override the value.
The answer seems to be: There is only one repository possible per entity.
I ended up using the #Subselect to create a second immutable entity and bound that to the second JpaRepsotory and setting it to #RestResource(exported = false), that also encourages a separation of concerns.
Employee Example
#Entity
#Table(name = "employee")
public class Employee {
#Id
Long id
String name
...
}
#RestResource
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {
}
#Entity
#Immutable
#Subselect(value = 'select id, name, salary from employee')
public class VEmployeeSummary {
#Id
Long id
...
}
#RestResource(exported = false)
public interface VEmployeeRepository extends JpaRepository<VEmployeeSummary, Long> {
}
Context
Two packages in the monolithic application had different requirements. One needed to expose the entities for the UI in a PagingAndSortingRepository including CRUD functions. The other was for an aggregating backend report component without paging but with sorting.
I know I could have filtered the results from the PagingAndSorting Repository after requesting Pageable.unpaged() but I just wanted a Basic JPA repository which returned List for some filters.
So, this does not directly answer the question, but may help solve the underlying issue.
You can only have one repository per entity... however, you can have multiple entities per table; thus, having multiple repositories per table.
In a bit of code I wrote, I had to create two entities... one with an auto-generated id and another with a preset id, but both pointing to the same table:
#Entity
#Table("line_item")
public class LineItemWithAutoId {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
...
}
#Entity
#Table("line_item")
public class LineItemWithPredefinedId {
#Id
private String id;
...
}
Then, I had a repository for each:
public interface LineItemWithoutId extends Repository<LineItemWithAutoId,String> {
...
}
public interface LineItemWithId extends Repository<LineItemWithPredefinedId,String> {
...
}
For the posted issue, you could have two entities. One would be the full entity, with getters and setters for everything. The other, would be the entity, where there are setters for everything, but only getters for the fields you want to make public. Does this make sense?
I have entity e.g. Product which aggregates other entities such as Category. Those entities can also aggregate other entities and so on. Now I need to test my queries to database.
For simple CRUD I would create mock of EntityManager. But what if I have more complex query which I need to test for correct functionality. Then I probably need to persist entity (or more of them) and try to retrieve/update, whatever. I would also need to persist all entities on which my Product depends.
I don't like such approach. What is the best way to test such queries?
Thanks for replies.
Update -- example
Lets assume following entity structure
This structure is maintained by JPA implementation. For example Product class would look like this
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#ManyToOne
private Category category;
#ManyToOne
private Entity1 something;
}
So now if I want to test any query used in DAO I need to create Product in database, but it is dependent on Category and Entity1 and there is #ManyToOne annotation so values cannot be null. So I need to persist those entities too, but they have also dependencies.
I'm considering pre-creating entities such Category, Entity1 and Entity2 before test using SQL script or dbunit (mentioned by #chalimartines) which would save large amount of code, but I don't know whether it is good solution. I would like to know some best practices for such testing.
you can use #TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) as
#ContextConfiguration(locations={"classpath:/path/to/your/applicationContextTest.xml"})
#RunWith( SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class YourClassTest {
#Test
public void test() {
//your crud
}
}
update
You cant set the dependecies to null in order to avoid to persist them
I don't know other way, but for persisting Product and its dependencies you can use testing framework DBunit that helps you setup database data.
I am trying to relate two tables with spring / hibernate in MYSQL like this
#Table (name = candidatresumeinfo)
public class CandidateResumeInfo implements Serializable
{
List<SelectedResumes> selectedResumes;
.............
..............
#JoinColumn(name = "selectedresumeid")
#OneToMany
public List<SelectedResumes> getSelectedResumes() {
return selectedResumes;
}
public void setSelectedResumes(List<SelectedResumes> selectedResumes) {
this.selectedResumes = selectedResumes;
}
Now ,i got the data in my list correctly( i checked in debug)but the call from server is getting failed which is saying cause:Nullpointer exception .
thanks
You can use OneToMany annotation only on Collections, so you should change the field to Set or List, because hibernate will return multiple result if you use OneToMany. I think you'd like to use ManyToOne annotation here.
ManyToOne means here that you have multiple CandidateResumeInfo for one SelectedResumes.
OneToMany means here that you have multiple SelectedResumes for one CandidateResumeInfo.
This annotation naming can be a bit strange for first time. Hope I helped.
Answer for your comment:
The best way is you declare the relationship both side.
Here is the example:
CandidateResumeInfo.java:
#OneToMany(mappedBy="candidateResumeInfo")
List<SelectedResumes> selectedResumes;
SelectedResumes.java:
#ManyToOne
#JoinColumn(name="candidate_resume_info_id")
CandidateResumeInfo candidateResumeInfo;