DEV Community

Cover image for Day 48: Defining Relations using TypeORM
Margaret W.N
Margaret W.N

Posted on

Day 48: Defining Relations using TypeORM

Defining relationships in typeORM has been the most confusing concept i've encountered today.

import { Column, Entity, PrimaryGeneratedColumn, OneToMany, ManyToOne } from "typeorm";

@Entity() 
class User {
  @PrimaryGeneratedColumn()
  public userId: string; 

  @OneToMany( type => Post, post => post.user)
  posts: Post[];
}

@Entity() 
class Post {
  @PrimaryGeneratedColumn()
  public postId: string; 

  @ManyToOne( type => User, user => user.posts)
  user: User;
}
Enter fullscreen mode Exit fullscreen mode

I've passed two parameters in @ManyToOne() and @OneToMany() The class it's 'related to' type => Postand a call back function. Below that are the posts and user attributes.

I still haven't wrapped my head around the call back function. It's like i get it but don't get it a the same time. I keep getting confused looking at the post => post.user and user => user.posts.

I definitely need help with this.
Day 48

Top comments (4)

Collapse
 
elthrasher profile image
Matt Morgan

Hi Margaret, I've used TypeORM for years and I sometimes still find that syntax confusing. Those decorators are taking a couple of functions (written as arrow functions) as arguments.

type => Post - this is a function that returns the type for the relation. For some reason the docs instruct us to give it an argument, but that arg is obviously not used so it could also be written () => Post or in longer form function() { return Post; }.

post => post.user - this time you're passing in an instance of an entity and returning one of its properties to map to the inverse relationship. It's basically a function you call that helps you find the property on the entity you have a relationship with that points back to the entity you're in.

You might wonder why this isn't more clear and that's basically because reflection (the ability of an object to introspect itself to answer questions like "what is the type of my foo property?") wasn't very advanced in TypeScript when TypeORM was designed.

The library is groundbreaking in the sense that it was built on language features that didn't quite exist yet. :) I think the 0.3.0 version is meant to be more clear, but I haven't completely kept up with it.

Hope that helps with your understanding.

Collapse
 
mtee profile image
Margaret W.N

Hi Matt, Thank you for the explanation. I'm closer to getting it that i was before. If i got that right, you're passing an instance post of the entity with the relation and accesing its property user. Question : Does posts: Post [ ] , create a column with posts in the entity User ?

Collapse
 
elthrasher profile image
Matt Morgan

Right, in the function post => post.user what it's asking is "what is the property on the entity I have a relationship with that points back to this entity?" In this case it is "I am a User and I have a relationship to Post. What property on Post represents me?"

In post => post.user post is just the name of the property TypeORM automatically passes in to figure out these relationships (so it could be foo => foo.user and would work the same). Part of the reason for this is you could have complicated mappings, like maybe instead of Post just having a User, presumably the User who wrote the Post, you could have Post having two different relationships with User, the original author and most recent editor. They can both have relationships with the same User entity, but will be different properties:

@Entity() 
class Post {
  @PrimaryGeneratedColumn()
  public postId: string; 

  @ManyToOne( type => User, user => user.editedPosts)
  editedBy: User;

  @ManyToOne( type => User, user => user.authoredPosts)
  writtenBy: User;
}
Enter fullscreen mode Exit fullscreen mode

Not sure that's the best design, but it'll give you an idea of more complex relationships.

Yeah posts: Post[] would indicate that the user has a relationship with many posts that would be mapped into an array if you executed the join query. By default the join query isn't executed so you'd need to specify an eager join or use a join relationship in the query builder to actually populate all the posts.

BTW a really good option when learning or debugging TypeORM is to enable logging in connection options. Any time you use an ORM it's important to connect the models to the SQL they eventually produce and TypeORM has a really good logger that will help you do that.

Thread Thread
 
mtee profile image
Margaret W.N

Woow, it is so clear right now. Thank you for taking your time to explain it to me. I'll jump right into it and expound on the topics you've linked. Very much appreciated 🙏.