How to relate two entities in Jhipster JDL? - jhipster

Let's say you have a Jhipster app that has a Profile and needs to register which Profiles follows other profiles with 2 attributes: one for the user that is following (user Profile) and another for the followed user (followed Profile). Something like:
entity Profile {
creationDate Instant required
}
entity Follows {
creationDate Instant
}
relationship OneToMany {
Profile{follows(user)} to Follows{profile(id)}
Profile{follows(followed)} to Follows{profile(id)}
}
The problem with this is that the Follows.java has 2 identical atributes even when the names are different follows(user) & follows(followed):
#ManyToOne
private Profile profile;
... instead of...
#ManyToOne
private Profile user;
#ManyToOne
private Profile followed;
Thanks.

You are using the same relationship name for both relationships, but each relationship name needs to be different or else the fields conflict.
relationship (OneToMany | ManyToOne | OneToOne | ManyToMany) {
<from entity>[{<relationship name>[(<display field>)]}] to <to entity>[{<relationship name>[(<display field>)]}]
}
JDL Relationship Declaration Docs
In the case of your JDL sample, I changed the display field from user/followed to id as those fields do not exist on the entity. The important change is that the relationship names are unique.
relationship OneToMany {
Profile{followed(id)} to Follows{followed(id)}
Profile{following(id)} to Follows{following(id)}
}

entity Profile {
creationDate Instant required
}
entity Follows {
creationDate Instant
}
relationship ManyToOne{
Follows{user} to Profile
Follows{followed} to Profile
}

Supposing you want relation between Rooms and Patient
You can have these entities
entity NmsPatient {
photo ImageBlob
}
entity NmsRoom {
code String required,
name String required
}
entity NmsPatientRoom {
begin ZonedDateTime,
end ZonedDateTime
}
And then
relationship ManyToOne {
NmsPatientRoom{patient} to NmsPatient,
NmsPatientRoom{room} to NmsRoom
}

Related

How can I use a contructor on an Entity that has properties with #ManyToOne decorator without passing instances of other entities and only their ids?

how can I use a constructor on an Entity that has properties with #ManyToOne decorator and their types are from another Entity but only with the primary key.
For example:
#Entity()
class User {
constructor(
idUser: number,
idExtraData: number
){
this.id = idUser;
// this is going to give an error because it requires an instance of ExtraData.
// but I would like to pass only the id
// and have an instance similar when I use findOne without populating anything
this.extraData = idExtraData;
}
#PrimaryKey()
id: number;
#ManyToOne()
extraData: ExtraData;
}
The instance of the entity I want should be similar to the instance returned by findOne without populating anything.
You can use Reference.createNakedFromPK()
#Entity()
export class Book {
#ManyToOne(() => Author)
author: Author;
constructor(authorId: number) {
this.author = Reference.createNakedFromPK(Author, authorId);
}
}
This instance will be either replaced with the managed entity during flush if there is one, or it will be merged to the EM otherwise.
(the docs mention how to do this with reference wrapper only, but its the same approach)
https://mikro-orm.io/docs/entity-references#assigning-to-reference-properties

JHipster many to many relationship with extra field

I've generated a ManyToMany relationship between two entities but I need to add a extra field in the join table
#ManyToMany
#JoinTable(name = "cliente_modulo",
joinColumns = #JoinColumn(name = "cliente_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "modulo_id", referencedColumnName = "id"))
private Set<Modulo> modulos = new HashSet<>();
In this way is added a new table in database but is not created a new entity.
How to generate a ManyToMany relationship that adds a entity with extra field?
Instead of a ManyToMany relation you can setup a OneToMany between Cliente and ClienteModulo and a ManyToOne between ClienteModulo and Modulo.
This should generate the join table as before but also the model entity and everything else you need.
Something like:
entity Cliente{}
entity ClienteModulo{}
entity Modulo{}
relationship OneToMany {
Cliente{clienteModulos} to ClienteModulo{cliente}
}
relationship ManyToOne {
ClienteModulo{modulo} to Modulo{clienteModulos}
}
Add the properties you need to ClienteModulo.

Jhipster User friend self relationship

I want to create a "friend" relationship between User using an entity "Friend".
I try this, but it isn't work.
entity Friend {
status Boolean,
modified LocalDate,
created LocalDate
}
relationship ManyToMany {
Friend{user(login)} to User,
User to Friend{user(login)}
}
How i can do that ?
Thanks
You cannot create relationship with User entity in JDL
A workaround is to create another entity and use a one-to-one relationship like this
entity Friend {
status Boolean,
modified LocalDate,
created LocalDate
}
entity UserExtended {
...
}
relationship OneToOne {
UserExtended to User
}
relationship ManyToMany {
Friend{userExtended(login)} to UserExtended,
UserExtended to Friend{userExtended(login)}
}
You may want to consider creating the relationship with the User directly in the generated code.
Found it :
entity UserExtra {
.....
}
entity Friend{
status Boolean,
modified LocalDate,
created LocalDate
}
relationship OneToOne {
UserExtended{user(login)} to User
}
relationship OneToMany {
UserExtended{friends} to Friend{user}
}
relationship ManyToOne {
UserExtended{friend} to UserExtended{users}
}

Why jhipster:import-jdl is giving me an IllegalAssociationException?

I have this UML:
entity Profile {
creationDate Instant required
bio String maxlength(7500)
}
entity Grupo {
creationDate Instant required
groupname String minlength(2) maxlength(100) required
image ImageBlob
isActive Boolean
}
// RELATIONSHIPS:
relationship OneToOne {
Profile{grupo} to Grupo{profile}
}
relationship OneToMany {
User{grupo} to Grupo{user(id) required}
}
// DTO for all
dto * with mapstruct
// Set pagination options
paginate all with pagination
// Set service options to all except few
service all with serviceImpl
and when I run it with yo jhipster:import-jdl it gives the following error:
IllegalAssociationException: Relationships from User entity is not supported in the declaration between User and Grupo.
Error jhipster:import-jdl ./src/main/scripts/raro.jh
Is it NOT allowed to have a OneToMany relationship with the User Entity? The thing is that OneToOne relationships works fine.
Because when I change the relationship to ManyToOne, it works
entity Profile {
creationDate Instant required
bio String maxlength(7500)
}
entity Groups {
creationDate Instant required
groupname String minlength(2) maxlength(100) required
image ImageBlob
isActive Boolean
}
// RELATIONSHIPS:
relationship OneToOne {
Profile{groups(groupname)} to Groups{profile}
}
// relationship OneToMany {
// User{groups} to Groups{user(id) required}
// }
relationship ManyToOne {
Groups{user(id) required} to User{groups}
}
// DTO for all
dto * with mapstruct
// Set pagination options
paginate all with pagination
// Set service options to all except few
service all with serviceImpl
Why? Am I doing something worng in the first example?
Thanks
JHipster does not allow OneToMany relationships to the user by default. If you need this, you will have to manually change the code.
Please note that the User entity, which is handled by JHipster, is specific. You can do:
many-to-one relationships to this entity (a Car can have a many-to-one relationship to a User)
many-to-many and one-to-one relationships to the User entity, but the other entity must be the owner of the relationship (a Team can have a many-to-many relationship to User, but only the team can add/remove users, and a user cannot add/remove a team)
https://www.jhipster.tech/managing-relationships/

How do you model roles / relationships with Domain Driven Design in mind?

If I have three entities, Project, ProjectRole and Person, where a Person can be a member of different Projects and be in different Project Roles (such as "Project Lead", or "Project Member") - how would you model such a relationship?
In the database, I currently have the following tablers: Project, Person, ProjectRole Project_Person with PersonId & ProjectId as PK and a ProjectRoleId as a FK Relationship.
I'm really at a loss here since all domain models I come up with seem to break some "DDD" rule. Are there any 'standards' for this problem?
I had a look at a Streamlined Object Modeling and there is an example what a Project and ProjectMember would look like, but AddProjectMember() in Project would call ProjectMember.AddProject(). So Project has a List of ProjectMembers, and each ProjectMember in return has a reference to the Project. Looks a bit convoluted to me.
update
After reading more about this subject, I will try the following: There are distinct roles, or better, model relationships, that are of a certain role type within my domain. For instance, ProjectMember is a distinct role that tells us something about the relationship a Person plays within a Project. It contains a ProjectMembershipType that tells us more about the Role it will play. I do know for certain that persons will have to play roles inside a project, so I will model that relationship.
ProjectMembershipTypes can be created and modified. These can be "Project Leader", "Developer", "External Adviser", or something different.
A person can have many roles inside a project, and these roles can start and end at a certain date. Such relationships are modeled by the class ProjectMember.
public class ProjectMember : IRole
{
public virtual int ProjectMemberId { get; set; }
public virtual ProjectMembershipType ProjectMembershipType { get; set; }
public virtual Person Person { get; set; }
public virtual Project Project { get; set; }
public virtual DateTime From { get; set; }
public virtual DateTime Thru { get; set; }
// etc...
}
ProjectMembershipType: ie. "Project Manager", "Developer", "Adviser"
public class ProjectMembershipType : IRoleType
{
public virtual int ProjectMembershipTypeId { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
// etc...
}
Here's how I would handle it:
class Person
{
string Name { get; set; }
IList<Role> Roles { get; private set; }
}
class Role
{
string Name { get; set; }
string Description { get; set; }
IList<Person> Members { get; private set; }
}
class Project
{
string Name { get; set; }
string Description { get; set; }
IList<ProjectMember> Members { get; private set; }
}
class ProjectMember
{
Project Project { get; private set; }
Person Person { get; set; }
Role Role { get; set; }
}
The ProjectMember class brings them all together. This model gives you the flexibility to assign the same Person to different Projects with different Roles (e.g. he might be a Developer on ProjectA, and a Tester on ProjectB).
Please don't create role specific classes - that lesson has been learnt already.
I've created a sample app to demonstrate this (it includes relationships too):
Run "bin\debug\RolesRelationshipsSample.exe"
Double-click the library icons to create entities
Drag/drop them to assign the appropriate relationships
Feel free to play with the code. Hope you find it useful.
You're modeling a many-to-many relationship: a project can have many people working on it, and a person can work on multiple projects.
You're modeling the relation as a Project Role, which in addition to serving as a bi-directional link from Person <-> Project, also records a RoleType and start/end of that Person filling that RoleType on that Project. (Notice how the English work "that" stands in for the database FK or, in code, a pointer/reference?)
Because of those FKs, we can in the database follow the graph from Person, through Project Role, to Project:
select a.person_id, b.project_role_id, c.project_id
from person a join project_role b on (a.id = b.person_id)
join project c on (b.project_id = c.id)
where a.person_id = ?
Or we can follow it in the other direction, from Project:
select a.person_id, b.project_role_id, c.project_id
from person a join project_role b on (a.id = b.person_id)
join project c on (b.project_id = c.id)
where c.project_id = ?
Ideally, we'd like to be able to do the same in the C# code. So yes, we want a Person to have a list, and Project to have a list, and a ProjectRole references to a Person and a Project.
Yes, Project::addPerson( Person& ) should really be Project::addProjectRole( ProjectRole& ), unless we decide that Project::addPerson( Person& ) is a convenience method of the form:
void Project::addPerson( Person& p ) {
this.addProjectRole( new ProjectRole( p, &this, RoleType::UNASSIGNED ) ;
}
A ProjectRole doesn't have a list, it has-a reference to a Person and a reference to a Project. It also has, as values, a start date, an end date, and a RoleType (which either is an enum, or a class instance that mimics an enum value -- that is, there is only one object per enum type, and it's stateless, immutable and idempotent, and thus sharable among many ProjectRoles).
Now this shouldn't mean that retrieving a Person from the database should cause the whole database to be reified in the object graph in the code; lazy proxies that retrieve only on use can save us from that. Then if we're only currently concerned with the Person, and not his Roles (and Projects, we can just retrieve the Person. (NHibernate, for instance, I think does this more-or-less seamlessly.)
Basically, I think that:
1) This is a standard way of representing many-to-many relations;
2) It's standard for a relation to have additional data (when, what kind of)
and; 3) you've pretty much got the right idea, and are just being rightly conscientious in getting feedback here.
Aren't you confusing the "Description" of a role with the role a person has in a project? Adding the "RoleDescription" concept (a 'role-class' so to speak), and "RoleInstance" objects referring to actual persons in projects may help.
What you have is a many-to-many relationship with additional data, the role. We have a similar structure except in our case a person may have multiple roles on a project, so I struggled with the same questions. One solution is to create a ProjectPerson class that extends Person and adds the role property:
public class ProjectPerson : Person
{
public string Role { get; set; }
}
Your Project class now has a collection of ProjectPerson but the Person class has a collection of Project because it doesn't make sense to extend the Project class to add role. You'll have to do some additional work (look up the Person in the ProjectPerson collection) to find the role on a Project from the Person's perspective.
A second solution is the standard way to handle many-to-many relationships with additional data. Create a ProjectRole class and model it as the many side of two one-to-many relationships from Project and Person. That is, both Project and Person each have a collection of ProjectRole.
It's important to consider how well your data access strategy will support the model in choosing a solution. You want to avoid scenarios where loading the collection requires one or more trips to the database for each object in the collection.
It appears that there are two main entities - Project and Project Member.
The Project Member has the attributes 'Member Role' and 'Member Name'. Either of these attributes may belong to a domain ie a set of values that can be maintained in lookup tables both for convenience and to use for searching. It is assumed that someone requires information about all project members carrying out a particular role/job.
Note. Lookup tables can have entries added but would not normally have the value of an entry changed. Once a value is selected from the lookup table then it is considered a permanent fixture of the owning table - in this case the Project Member table.
I wouldn't expect to see a 'Person' entity or table in any business other than the convenience as a lookup table as in the case above. HR departments will keep a list of employees that have specific information that is required by Payroll etc. but there is nothing fundamental abut People that the business will need to know. NB Locate the business process to identify an entity - don't make it up.

Resources