JPA: From entities, query other entities with no relational mapping between them - jpa

My question is probably so simple, that I can't find an answer for it.
I want to do something like this:
#Entity
public class EntityA {
#Transient
#SomeQueryAnnotation(query="select b from EntityB where b.id=1")
private EntityB entityB;
}
EntityB is kind of static resource. It should not be saved back to the database. There is also no mapping between the entities.
[EDIT]
Do you think it was ok, when I do this:
#Entity
public class EntityA {
private EntityB getEntityB() {
ServiceRemote service = (ServiceRemote)context.lookup("ejb:ServiceRemote");
return service.getEntityB();
}
}
Than it should still be possible to use remoting, because the connection can be configured in each clients' jndi.properties file. what is your prefered method when you need to access the database from your entities?

Best recommendation - Unless these objects have an in-database relation, then there shouldn't be an entity relationship.
Second best - I would recommend you create a data transfer object to fetch your object.
#Entity
public class EntityA {
#Transient
private EntityB entityB;
}
#Stateless
public class EntityADTO {
EntityManager em;
public EntityA findA(Object pkey) {
EntityA a = em.find(okey, EntityA.class);
a.entityB = em.find(1, EntityB.class);
return a;
}
}

Related

Spring Data Neo4j 6: findAll() operation doesn't map relationships properly

In Spring Data Neo4j 6 (6.0.1), a basic Neo4jTemplate findAll() operation with a simple relationship doesn't seem to map the relationship entity and its target even though they are part of the result set. Is this a bug or am I missing something?
Let's consider the following basic scenario:
var a = new EntityA();
var b = new EntityB();
a.entityB = b;
neo4jTemplate.save(a);
with
#Node
public class EntityA {
#Id #GeneratedValue(UUIDStringGenerator.class)
public String id;
#Relationship("HAS_ENTITY_B")
public EntityB entityB;
}
#Node
public class EntityB {
#Id #GeneratedValue(UUIDStringGenerator.class)
public String id;
}
When trying to map a result like this:
var result = neo4jTemplate.findAll("MATCH (a:EntityA)-[r:HAS_ENTITY_B]->(b:EntityB) RETURN a,r,b", EntityA.class);
Assert.notNull(result.get(0).entityB, "entityB should not be null here!");
I would expect the entityB property not to be null.
That's certainly not the expected behavior, but you should write your query this way:
MATCH (a:EntityA)-[r:HAS_ENTITY_B]->(b:EntityB) RETURN a, COLLECT(r), COLLECT(b)
For now, it looks like there is a lack of documentation and implementation regarding custom queries and relationships in SDN 6 (see this ticket and this one).

how to filter out entity object inside entity in rest api

I am using Spring Boot to implement rest api. There are three entities SeqTb, PairTb, and GroupTb and they are nested. SeqTb has manytoone with PairTb. PairTb has onetomany relationship with SeqTb and also manytoone with GroupTb.
//SeqTb.java
#Entity
#Table(name="SEQ_TB")
public class SeqTb implements Serializable {
.......
#ManyToOne
#JoinColumn(name="PAIR_ID")
private PairTb pairTb;
......
}
// PairTb.java
#Entity
#Table(name="PAIR_TB")
#NamedQuery(name="PairTb.findAll", query="SELECT p FROM PairTb p")
public class PairTb implements Serializable {
#ManyToOne
#JoinColumn(name="GROUP_ID")
private GroupTb groupTb;
#OneToMany(mappedBy="pairTb", cascade=CascadeType.ALL)
private List<SeqTb> seqTbs;
}
//GroupId.java
#Entity
#Table(name="GROUP_TB")
public class GroupTb implements Serializable {
//bi-directional many-to-one association to PairTb
#OneToMany(mappedBy="groupTb", cascade=CascadeType.ALL)
private List<PairTb> pairTbs;
}
In my controller GET request with analysisId was handled in the following way:
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SeqTb> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
SeqTb seq = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seq, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
When I query a SeqTb object with SeqTb.PairTb == null, the api works just fine. However, if the analysisId I put in the url belongs to a SeqTb record that associates with a pairId which in turn belongs to a groupId, the program would go nuts. Below is the output, the first part output is correct (bold text). After that it keeps printing PairTb and GroupTb in loops (repeating keywords pairTb, groupTb).
{"rowId":8,"analysisId":"cce8d2c2-a6dc-4ee9-ba97-768f058abb50","analyteCode":"D","center":"UCSC",
"pairTb":{"rowId":4,"pairCode":"01ad975d-c2ed-4e4d-bd3b-c9512fc9073c","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":[{"rowId":1,"pairCode":"00ad0ffe-2105-4829-a495-1c2aceb5bb31","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":
Meanwhile I got lots of errors from tomcat server:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:565) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
How do I ignore the nested entity object inside an entity and get only the meaning columns?
You can also annotate a property with #JsonIgnore in order to not output that field.
Found the solution. Created a value object that only contains the specific columns from entity and leave out the nested entity object. And it works.

Query to find Parent entity by Child attribute where Parent also have same attritube, in spring data jpa

I am trying to create a query in Spring-data-jpa to find a Person entity by Address's id. Person have OneToOne relationship with Address and both have id as primary key.
public abstract class AbstractEntity{
#Id
Long id;
}
public class Person extends AbstractEntity {
#OneToOne
Address address;
}
public class Address extends AbstractEntity {
}
public interface PersonRepository implements JpaRepository<Person, Long> {
Person findByAddressId(Long addressId); // Throws cannot create metamodel exception
Person findByAddress_Id(Long addressId); // Throws cannot create metamodel exception
}
I'm thinking that the method name findByAddressId and findByAddress_Id are ambiguous for Spring data jpa query look-up strategies as both Person and Address entities have id as their attributes.
Is it possible to write query in Spring-data-jpa to find parent entity by child attribute where parent and child both have same attribute, without writing SQL?

EF CTP5 POCO, base class and how to implement inheritance

Hey,
lets say I want all my recordsto have a standard stamp on them.
inserted_by, inserted_at, updated_by, updated_at, deleted_by, deleted_at, timestamp
1 - If I had to put this in a base (maybe abstract) POCO class, what would be the best inheritance strategy to implement this. (I am using GUID as primary keys.)
I do not want to use base class for anything else.
In my Db Context;
I'd like to use the end POCO classes that corresponds to the db table.
DbSet, looks like I have to use DbSet tough, then use OfType to query:)
2 - If Inheritance is out of context, what would you recommend, ComplexType, an Interface maybe?
I do exactly that in EF4. There is a generic repository base class:
public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
All entity repositories inherit from this class. The generic .Add() and .Update() method automatically set the audit data:
public void Add(T entity)
{
entity.CreatedOn = DateTime.UtcNow;
entity.CreatedBy = UserName;
entity.LastModifiedOn = entity.CreatedOn;
entity.LastModifiedBy = entity.CreatedBy;
ObjectContext.AddObject(GetEntitySetName<T>(), entity);
}
public void Update(T entity)
{
T originalEntity = ObjectSet.Single(t => t.Id == entity.Id);
entity.CreatedOn = originalEntity.CreatedOn;
entity.CreatedBy = originalEntity.CreatedBy;
entity.LastModifiedOn = DateTime.UtcNow;
entity.LastModifiedBy = UserName;
ObjectSet.ApplyCurrentValues(entity);
}
So you can see that it doesnt go into the POCO base class BaseEntity, because it's not the responsibility of the POCO. Instead it belongs to the Repository.
You need TPC inheritance (Table per class or Table per concrete type). Check this article about CTP5 mapping of TPC.

How do I represent this using JPA?

I would like a 'RolesPlayed' entity with the following columns
user
role
department/project/group
All the three columns above constitute a composite primary key. I would like to know if defining a column to be one of department/project/group possible ? If yes, how ? Or do I need to break the entity into DepartmentRoles, GroupRoles and ProjectRoles.
Thanks.
You could use polymorphism with an abstract base class to do that.
#Entity
public class RolePlayed {
#ManyToOne
private User user;
#ManyToOne
private Role role;
#ManyToOne
private Body body;
...
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Body {
...
}
#Entity
public class Department extends Body {
...
}
#Entity
public class Project extends Body {
...
}
#Entity
public class Group extends Body {
...
}
Check out the Polymorphism section in the Java Enterprise tutorial for a good overview.
Alternatively, you could also make the RolePlayed entity abstract, with DepartmentRole, GroupRole and ProjectRole implementations.