#ManyToMany annotated list of strings? Is it ever possible? - jpa

I have users and each user has several roles. Roles and users are in many-to-many relationship. But the role is just a name. I've got stuck in this phase:
#ManyToMany
#JoinTable(name="users2roles")
private Collection<String> roles;
There is missing the name of target table. I was searching on Internet, but nothing have found. I don't wannt to create special entity class to wrap one string value. Is there some another way, isn't?
Is there any way to make it work or makes JPA me create a new entity?

A Collection of Strings isn't relating one object to another so cannot be a #OneToMany or #ManyToMany - ought to be #ElementCollection. It's a collection of Strings, nothing more. Yes, it can be stored in a join table, but using #CollectionTable.

Related

Simple Tagging Implementation with Spring Data JPA/Rest

I am trying to come up with a way of implementing tags for my entity that works well for me and need some help in the process. Let me write down some requirements I have in mind:
Firstly, I would like tags to show in entities as a list of strings like this:
{
"tags": ["foo", "bar"]
}
Secondly, I need to be able to retrieve a set of available tags across all entities so that users can easily choose from existing tags.
The 2nd requirement could be achieved by creating a Tag entity with the value of the Tag as the #Id. But that would make the tags property in my entity a relation that requires an extra GET operation to fetch. I could work with a getter method that resolves all the Tags and returns only a list of strings, but I see two disadvantages in that: 1. The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case. 2. The process of creating an entity requires to create all the Tags via a /tags endpoint first. That seem rather complicated for such a simple thing.
Also, I think I read somewhere that you shouldn't create a repository for an entity that isn't standalone. Would I create a Tag and only a Tag at any point in time? Nope.
I could store the tags as an #ElementCollection in my entity. In this case I don't know how to fulfill the 2nd requirement, though.
#ElementCollection
private Set<String> tags;
I made a simple test via EntityManager but it looks like I cannot query things that are not an #Entity in a result set.
#RestController
#RequestMapping("/tagList")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TagListController implements RepresentationModelProcessor<RepositoryLinksResource> {
#PersistenceContext
private final #NonNull EntityManager entityManager;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<EntityModel<TagList>> get() {
System.out.println(entityManager.createQuery("SELECT t.tags FROM Training t").getFirstResult());
EntityModel<TagList> model = EntityModel.of(new TagList(Set.of("foo", "bar")));
model.add(linkTo(methodOn(TagListController.class).get()).withSelfRel());
return ResponseEntity.ok(model);
}
}
org.hibernate.QueryException: not an entity
Does anyone know a smart way?
The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case
This is precisely the issue with using entities as REST resource representations. They work fine until it turns out the internal representation (entity) does not match the external representation (the missing DTO).
However, it would probably make most sense performance-wise to simply use an #ElementCollection like you mentioned, because you then don't have the double join with a join table for the many-to-many association (you could also use a one-to-many association where the parent entity and the tag value are both part of the #Id to avoid a join table, but I'm not sure it's convenient to work with. Probably better to just put a UNIQUE(parent_id, TAG) constraint on the collection table, if you need it). Regarding the not an entity error, you would need to use a native query. Assuming that you have #ElementCollection #CollectionTable(name = "TAGS") #Column(name = "TAG") on tags, then SELECT DISTINCT(TAG) FROM TAGS should do the job.
(as a side note, the DISTINCT part of the query will surely introduce some performance penalty, but I would assume the result of that query is a good candidate for caching)

JPA ManyToMany relationship -- Why would association (join) table be empty

I have two entities Account and Position. The POSITION table and the ACCOUNT table have contents but the POSITION_ACCOUNT table, which I think should have at least one row, is empty. What could I be doing wrong? Here is the relevant code (I am using EclipseLink 2.4.2:
In Position:
#ManyToMany
private List accounts;
In Account:
#ManyToMany(mappedBy = "accounts",fetch=FetchType.EAGER,cascade=CascadeType.PERSIST)
#JoinTable(name="POSITION_ACCOUNT")
Confusing to me and perhaps relevant is that some examples I see annotate the getters and setters but others, as I am doing here, annotate the actual Lists.
It turns out that I needed to specify cascade=CascadeType.PERSIST on both sides of the relationship but there were other application-specific issues along the way. I don't know if reading the original question or this answer will be of much help to anyone. Sorry.

JPA Multiple relationships on one field in an entity

I am a beginner to using JPA 2.0 and databases in general and I was just confused about a few concepts.
So I have a total of 3 tables. One is the UserTable, which contains all the information about my user. It has a primary key field called user_Id. My other two tables are ExercisesTable and FoodIntakeTable, and they each have a foreign key field called user_Id to reference the user_Id in my UserTable. I want a one-to-many relationship from my user_Id table to each of the two tables so I can find pull out exercise information or food information for a user.
Pretty much like this:
FoodIntakeTable <-> UserTable <-> ExercisesTable
I need a bidirectional mapping from UserTable to FoodIntakeTable and also a bidirectional mapping from UserTable to ExercisesTable from the field user_Id.
The problem is, when I try to write my code like this in my Usertable class:
#OneToMany(mappedBy="ExercisesTable.userId")
#OneToMany(mappedBy="FoodIntakeTable.userId")
public long userId;
It's illegal because I can't have two #OneToMany annotations on the same field. I think it's supposed to be legal in a normal relational database and I'm just confused about how you translate this into JPA. I'm very new to the whole concept of databases and entities in general, so any help would be appreciated.
In JPA you can directly reference entity objects instead of the ids that they are mapped by. Try something like this:
You should have an entity type for each of your tables, say Exercise for ExercisesTable, FoodIntake for FoodIntakeTable, and User for your UserTable.
Then your User entity is the owning side of the relationships, having one field per relationship like this:
#OneToMany(mappedBy=...)
private List<Exercise> exercises;
#OneToMany(mappedBy=...)
private List<FoodIntake> foodIntakes;

A select JPA query that ignores the related entities of one-to-many relation, is that possible?

I am new in JPA, so excuse me if my question seems basic.
I have an entity called User, which is related to a list of other entities like follow:
#OneToMany(cascade = CascadeType.ALL , mappedBy = "user")
private List<session> sessionList;
In a controller class, I defined a find method in a RESTFull manner like follow:
#GET
#Path("/Users")
#Produces("application/json")
public List<UserDevice> findAllUsers()
{
return em.createQuery("SELECT u FROM User u").getResultList();
}
The returned result contains all the sessions of the users which is normal, but make the result huge though I just want to retrieve the basic information of the users (all the simple columns).
My question is: is it possible to ignore the related entities and just keep the columns of the actual entity? Thank you very much
Unless you explicitely map the association as eagerly loaded (using #OneToMany(fetch = FetchType.EAGER)), the above query should only return the fields of the users, and should not load their sessionList.
If the sessions are loaded, then the association is marked as eagerly loaded, or you load them lazily by calling a method of the List<Session>.

How to model a many to one relationship with a string?

My entity has a String property. many instances of the entity share the same string. So for query performance i want to configure a many-to-one relationship for this string.
To use the jpa-annotation would need to write a new entity class that only caries the string and reference the new entity. In my opinion this would be kind of overkill.
Is it possible to configure jpa so the string is externalized to a new table with one row per distinct value?