How to map OneToMany relationship from Superclass - jpa

Hello! Recently I was stuck with such problem, and I hope the solution I provide below will help some other JPA newbies like me. If there is better solution please post it here!
The problem is as follows:
I want to create OneToMany relationship from classes Book and CD to class Tag.
In order to unify all the logic regarding class Tag from Book and CD I create #MappedSuperclass class Item, and make Book and CD descendants of class Item. But when I try to map
List <Tag>
tags with #OneToMany” in that superclass I get nothing good..

My solution:
In order to do an ORM mapping one should understand first what he actually wants to see in the database. So when I realized that reasonable solution is to create several transition tables between descendants of Item and Tag, I understood, that this may be accomplished using #ManyToMany. And it works fine!
Listing below.
#MappedSuperclass
public class Item extends Model {
#Id
public Long id;
#ManyToMany(cascade = CascadeType.ALL)
public List<Tag> tags;
public String name;
<…> }
#Entity
public class Book extends Item {
public int pageNum;
<…> }
#Entity
public class CD extends Item{
public int size;
<…> }
#Entity
public class Tag extends Model{
#Id
public Long id;
public String text;
<…> }
PS I'd post also class and er diagrams, but currently I got no r8n to post images.

Related

How can I get data from #DBRef document using #Query -> Spring data mongo

I need help to get the data from another document I have the following class.
#Data
#Document(collection = "tmVersion")
public class TmVersion {
#Id
private String id;
private String cVrVersionId;
#DBRef
private TaApplicationVersion taApplicationVersion;
}
and
#Data
#Document(collection = "taApplicationVersion")
public class TaApplicationVersion {
#Id
private String id;
private String dVrAppName;
private String dVrAppCode;
}
This is my repository in which I map what I want to be shown but in taApplicationVersion I need to show all this object also how is it done?
#Query(value="{}", fields="{'cVrVersionId': 1, 'taApplicationVersion.dVrAppName': 2,
'dVrVersionNumber': 3}")
Page<TmVersion> getAllVersionWithOutFile(Pageable pageable)
Couple of things to mention here.
If you want this kind of join between tables, then you need to rethink your choice of Mongodb as database. No Sql Databases thrive on the fact that there is very less coupling between tables(collections). So if you are using #DBRef, it negates that. Mongodb themselves do not recommend using #DBRef.
This cannot be achieved with the method like you have in the repository. You need to use Projections. Here is the documentation for that.
Create a Porjection interface like this. Here you can control which fields you need to include in the Main class(TmVersion)
#ProjectedPayload
public interface TmVersionProjection {
#Value("#{#taApplicationVersionRepository.findById(target.taApplicationVersion.id)}")
public TaApplicationVersion getTaApplicationVersion();
public String getId();
public String getcVrVersionId();
}
Change the TmVersionRepository like this
public interface TmVersionRepository extends MongoRepository<TmVersion, String> {
#Query(value="{}")
Page<TmVersionProjection> getAllVersionWithOutFile(Pageable pageable);
}
Create a new Repository for TaApplicationVersion. You can add #Query on top of this method and control which fields from subclass needs to be returned.
public interface TaApplicationVersionRepository extends MongoRepository<TaApplicationVersion, String> {
TaApplicationVersion findById(String id);
}

Model superclass for JPA in Play Framework in 2.3.x Java

I'm trying to use JPA in Play Framework for Java version 2.3.7.
Before in Play 1.x, there was a Model superclass that made it really easy to execute queries like "List persons = Person.findAll();".
Is there Model superclass for javaJpa to do this?
There is no play.db.jpa.Model class for Play 2
But you can use play.db.jpa.JPA
and to find all do
JPA.em().createQuery("select p from Person p").getResultList();
where the create query contains JPQL and Person is entity name .
For more details check sample/computer-database-jpa.
Also check Play Docs,Similar
I think there's no play.db.jpa.Model on play 2.
The closest thing should be Ebean and SpringJPA which I use and recommend because of Ebean being soon removed in favor of JPA and being JPA mature and well documented.
As a quick example, those should look like:
Ebean
FindAllUsage
List<Person> people = Person.find.all();
Person model
#Entity
public class Person extends Model
{
#Id
public Long id;
public String value;
public static final Model.Finder<Long, UserPermission> find =
new Model.Finder<Long, UserPermission>(Long.class,UserPermission.class);
}
SpringJPA
FindAllUsage
List<Person> people = personRepository.findAll();
Person repository
#Named
#Singleton
public interface PersonRepository extends CrudRepository<Agent,Long> {
}
Person model
#Entity
public class Person
{
#Id
public Long id;
public String value;
}
In Play 2 the Model class is extending Ebean ORM by default and it has these general methods as save, update, find.byId, find.all etc.

What is a right way to map composite relationships in JPA?

I have a class called Topic, which may have prerequisites which are other Topics. What is the right way to map such a relationship. Should I do something like this ?
The Model you see below is a Play Framework Model class.
#Entity
public class Topic extends Model {
#OneToMany
public Set<Topic> prerequisites;
}
Or should I use another model class to manage the pre-requisite relationship ?
#Entity
public class TopicPrerequisites extends Model {
#OneToOne
public Topic theTopic;
//or maybe this should be #ManyToMany ???
#OneToMany
public Set<Topic> prerequisites;
}
Can a Topic be a pre-requisite for more than one Topic? If so, I would do the following:
#ManyToMany
private List<Topic> prerequisites;
#ManyToMany(mappedBy="prerequisites")
private List<Topic> topics;
An extra Entity for the relation would be unnecessary in my view.

JPA Inheritance :mapping derived entities to different tables

I use SINGLE_TABLE inheritance startegy to map my usres (see code example bellow).
Is there a way to map UnActiveRegularUser and UnActiveBusinessUser from "ACTIVE_USERS" table to another table, for example "UNACTIVE_USERS" and keep the inheritance startegy?
Note:
-The point here is to avoid code duplication between ex. RegularUser Vs UnActiveRegularUser (since they use the same properties) but still to map them to 2 different tables: "ACTIVE_USERS" and "UNACTIVE_USERS".
-strategy = InheritanceType.SINGLE_TABLE should not be changed.
-May adding another abstraction layer solve this problem?
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "ACTIVE_USERS")
public class User {
#Id #GeneratedValue
protected Long id;
#Column(nullable = false)
protected String name;
}
#Entity
public class RegularUser extends User{
//more getters and settres
}
#Entity
public class UnActiveRegularUser extends User{
//same getters and setters as in RegularUser
}
#Entity
public class BusinessUser extends User {
//more getters and settres
}
#Entity
public class UnActiveBusinessUser extends User {
//same getters and setters as in BusinessUser
}
Thanks,
Nathan
Persisting fields to another table won't prevent code duplication. I think you should just make UnActiveBusinessUser extend BusinessUser, and UnactiveRegularUser extend RegularUser.
Note that if a user can become unactive (i.e. it is a RegularUser and becomes an UnactiveRegularUser), inheritance is not the right solution: an object can't go from one type to another. Since it seems UnactiveRegularUser doesn't have anything more than RegularUser, I'm not sure this subclass is useful.

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.