Relationships

Entities in your data model may reference each other. For example, you might want to introduce a User entity to the todo list example from the quick start guide that looks like this:

@Entity
class User {
    
    @Id
    @GeneratedValue
    public long id;
    
    @Column(nullable = false)
    public String firstName;
    
    @Column(nullable = false)
    public String lastName;

    @Projection(name = "baseProjection", types = {User.class})
    interface BaseProjection {
        long getId();
        String getFirstName();
        String getLastName();
    }
}

Backend

Now you want to associate each User with a list of TodoItems. You can do this by adding the following attribute to the TodoItem entity class:

@ManyToOne(optional = false)
public User creator;

Take note that in this case, it is also required to specify whether the User is optionally associated with a TodoItem, so the creator property may be null, or not. Also you must not add a corresponding getter (or val in case of Kotlin) to your base projection, since the base projection should only cover primitive properties.

Now each TodoItem is associated with one User that you can access in the Typescript frontend as follows (the Kotlin frontend works analogous):

If you want to go the other way around and access all TodoItems that belong to a certain User, you have to add the corresponding property to the User class:

@OneToMany(mappedBy = "creator")
public List<TodoItem> todos;

In this case you do not need to specify nullability because @OneToMany and @ManyToMany relationships will never be nullable since they may just contain an empty list.

Accessing the TodoItems for a User works analogous to the reverse access discussed before, but the call to readTodos will of course return a promise with an array of values.

If you specify your entities this way, a single TodoItem may belong to only a single User. FeGen also supports the use of @ManyToMany relationships on both sides to lift this restriction. In the frontend, accessing related items works the same as with @OneToMany relationships.

If you wanted to add a associate an address entity with each user, and each address may only belong to one user, you can use a @OneToOne relationship on both sides, which is also supported by FeGen and works like the @ManyToOne relationship in the frontend.

Frontend

To access related entities in the generated code, you have two options.

The first one is to use projections which enable you to fetch an entity and a whole set of (even transitively) related entities in one api call. To see how they work, refer to the page Projections.

The other one is using the methods that are generated into the API clients of the entities that contain the relationships.

For example, if you added the creator property to your TodoItem entity, you can now use the readCreator method to retrieve Users associated with a specific TodoItem.

const todoItems: TodoItem[] = (await apiClient.todoItemClient.readAll()).items;
const todoItem = todoItems[27];
const user: User = await apiClient.todoItemClient.readCreator(todoItem);

Such a read method is generated for all relationships mentioned earlier, although @OneToMany and @ManytoMany relationships will of course return an array instead of a single value. The corresponding Kotlin code is analogous.

You can use the following methods to add or remove relationships between entities. It is important that all the objects passed to such a set method have already been created in the backend. Conversely, the todosToDelete object will not be deleted from the database.

apiClient.userClient.setTodos(user, todos);
apiClient.userClient.deleteFromTodos(user, todosToDelete);

If your relationship is @OneToMany or @ManyToMany, you can use the following method to add a single object to the relationship without removing the others.

apiClient.userClient.addToTodos(room, todoToAdd);