I have an entity Message that has a sender
(User
) and a receiver
, but the receiver
can either be a User
or a Channel
(both entities have the messagesIn
member), and I want to implement this using TypeORM relationships.
Would It be possible to do something like this with TypeORM(postgres)/NestJS (Or is there any conventional other way to achieve the same goal) ?
// message.entity.ts
@Entity()
export class Message {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
content: string;
@ManyToOne(() => User, (snd) => snd.messagesOut)
sender: User;
// That line doesn't compile
@ManyToOne(() => User | Channel, (rcv) => rcv.messagesIn)
receiver: User | Channel;
};
2
Answers
You cannot have a column which is a foreign key either of multiple tables; a FK must always reference a specific column/column set in a single table. You handle this situation by defining a nullable column(s) referencing each table, then place a constraint requiring one of them to be null. Unfortunately I am not familiar enough with your obscurification manager (TypeORM) so I will also provide a raw Postgres table definition.
Of course that makes assumptions about you tables, their keys and column types.
What you’re trying to do isn’t possible because TypeORM needs to know exactly what entity you are trying to populate so then it can query in the right place.
TypeORM has some mechanisms that allows you to create a single table that all the records, both from User and Channel, will be inserted in, see more here.
But, if you want to have two dedicates table for each entity (aka Table Per Type Inheritance), I would suggest create another entity called
Receiver
that contains common properties, that are related to the messaging mechanism, betweenUser
andChannel
, plus a property calledtype
, that will define if the Receiver is aUser
or aChannel
; and then reference theReceiver
entity in each one of the two tables.Then, in the
Message
entity, you will be able to referenceReceiver
:So, when you get a Message entity through the repository, you will receive something like:
With this information in hands, you will be able to access the data that you want and is necessary for the message sending flow, and, if you need some specific information that is only present in the
User
orChannel
entity, you can get thetype
fromReceiver
and retrieve the respective entity by the receiver id, something like: