I am trying to return and entity including its relation but I am getting an error saying relation xxx not found. I am using the repository pattern.
#Entity({ name: 'person' })
export class PersonEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'number' })
statusId: number;
#ManyToOne(() => StatusEntity, status => status.id)
status: StatusEntity;
}
#Entity({ name: 'statuses' })
export class StatusEntity {
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ type: 'varchar', length: 256 })
name: string;
}
I am using postgres and I have a foreign key declared:
"public"."person" ADD CONSTRAINT "FK_person_statusid" FOREIGN KEY ("statusId") REFERENCES "public"."statuses"("id")
In my service:
public async getAll(): Promise<PersonEntity[]> {
return await this.personRepository.find({ relations: ['statuses'] });
}
#Entity({ name: 'person' })
export class PersonEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'number' })
statusId: number;
#ManyToOne(() => StatusEntity)
#JoinTable()
status: StatusEntity;
}
#Entity({ name: 'status' })
export class StatusEntity {
#PrimaryGeneratedColumn()
id: number;
#Column({ type: 'varchar', length: 256 })
name: string;
}
Note that I have changed StatusEntity name from statuses to status.
Could you delete the foreign key you created manually, and then update your entity like below and try?
#Entity({ name: 'person' })
export class PersonEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'number' })
statusId: number;
#ManyToOne(() => StatusEntity)
#JoinColumn({ name: 'statusId })
status: StatusEntity;
}
Related
I have set up a many to many relation between a user table and a spot table.
Here is the user entity:
#Entity('user')
export class UserEntity {
#PrimaryGeneratedColumn()
id: number;
#Column({ default: '' })
first_name: string;
#Column({ default: '' })
last_name: string;
#Column({ default: '' })
email: string;
#Column({ default: '' })
adress: string;
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
#ManyToMany(() => SpotEntity, (spot) => spot.users)
#JoinTable({
name: 'spot_user',
joinColumn: {
name: 'user_id',
referencedColumnName: 'id',
},
inverseJoinColumn: {
name: 'spot_id',
referencedColumnName: 'id',
},
})
spots: Spot[];
}
And here is the spot entity:
#Entity('spot')
export class SpotEntity {
#PrimaryGeneratedColumn()
id: number;
#Column({ default: '' })
title: string;
#Column({ default: '' })
description: string;
#Column({ default: '' })
address: string;
#Column({ default: '' })
coordinates: string;
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
#ManyToOne(() => TagEntity, (tag) => tag.spots)
tag: TagEntity;
#ManyToMany(() => UserEntity, (user) => user.spots)
users: User[];
}
This creates the join table as it should.
But now I am a bit confused as to how add a spot to a user.
To do so I added a service like so, which has access to both user and spot repository:
I a able to get the spot and the user, but the spot never saves into the user, and the join table is never updated.
async addSpotToUser(id?: number, spotId?: number): Promise<void> {
const mySpot = Object.values(spotId)[0];
const user = await this.userRepository.findOneBy({ id: Number(id) });
const spot = await this.spotRepository.findOneBy({ id: mySpot });
user.spots.push(spot);
this.userRepository.save(user);
}
}
I'm working on a nestjs project with TypeORM. I'm setting up a bidirectional ManyToMany relationship between two entities: Notes and Gcalevents. Every Note could be linked to multiple Gcalevents, and every Gcalevent could be linked to many Notes.
Snippets from my entity definitions look like this:
base.entity.ts:
export class BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'boolean', default: true })
isActive: boolean;
... // some more fields
}
note.entity.ts:
import { Gcalevent } from './gcalevent.entity';
import { BaseEntity } from './base.entity';
#Entity({ name: 'note' })
export class Note extends BaseEntity {
#Column({ type: 'varchar', length: 300 })
title: string;
...
#ManyToMany(() => Gcalevent, (gcalevent) => gcalevent.notes)
#JoinTable()
gcalevents: Gcalevent[]
}
gcalevent.entity.ts:
import { Note } from "./note.entity";
#Entity({ name: 'gcalevent' })
export class Gcalevent {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({
type: 'varchar',
nullable: false,
})
eventId: string;
...
#ManyToMany(() => Note, (note) => note.gcalevents)
notes: Note[]
}
I believe I'm declaring the ManyToMany relationships correctly, but when I try to generate the TypeORM migration, I get the error TypeError: Class extends value undefined is not a constructor or null, which points to both the note.entity and gcalevent.entity files
I'm guessing this has something to do with the gcalevent.entity and note.entity files importing each other, combined with the note.entity file importing BaseEntity, but not sure how to fix it!
I had the same problem, I've found here
this "workaround" for the issue.
Try using "strings" instead of "types" in the #ManyToMany decorator:
note.entity.ts:
import { Gcalevent } from './gcalevent.entity';
import { BaseEntity } from './base.entity';
#Entity({ name: 'note' })
export class Note extends BaseEntity {
#Column({ type: 'varchar', length: 300 })
title: string;
...
#ManyToMany("Gcalevent","notes")
#JoinTable()
gcalevents: Gcalevent[]
}
gcalevent.entity.ts:
import { Note } from "./note.entity";
#Entity({ name: 'gcalevent' })
export class Gcalevent {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({
type: 'varchar',
nullable: false,
})
eventId: string;
...
#ManyToMany("Note","gcalevents")
notes: Note[]
}
Have got error 'Cannot read properties of undefined (reading 'joinColumns')'
How to implement: user can have only one assigned role with permissions to resources?
I used sequilize before, in typeorm I'm newbee
user_roles table entity:
#Entity({ name: 'user_roles' })
export class UserRoleEnitity extends DateAudit implements IUserRole {
#Column('varchar')
name: string;
#Column('varchar', {
nullable: true,
})
description?: string;
#Column('boolean', {
name: 'is_active',
default: false
})
isActive?: boolean;
#OneToMany(() => RolePermissionsEnitity, permission => permission.id)
permissions: IUserRolePermission[];
}
and users entity:
#Entity({ name: 'users' })
export class UserEnitity extends DateAudit implements IUser {
#JoinColumn({ name: 'role_id' })
roleId: string;
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
#Column('varchar', {
unique: true,
})
username: string;
#Column('varchar')
password: string;
#Column('varchar', {
nullable: true,
})
email?: string;
#Column('varchar', {
name: 'mobile_number',
nullable: true,
})
modileNumber?: string;
#Column('varchar', {
nullable: true,
})
name?: string;
#Column('varchar', {
nullable: true
})
position?: string;
#Column({
name: 'is_verified',
default: true
})
isVerified?: boolean;
#Column('timestamp', {
name: 'password_modified_at',
default: new Date()
})
passwordModifiedAt?: Date;
}
and role_permissions
#Entity({ name: 'user_role_permissions' })
export class RolePermissionsEnitity extends DateAudit implements IUserRolePermission {
#JoinColumn({ name: 'role_id' })
roleId: string;
#ManyToOne(() => UserRoleEnitity)
role: IUserRole;
#Column({
type: 'enum',
enum: Actions,
default: Actions.READ
})
action: Actions;
#JoinColumn({ name: 'resource_id' })
resourceId: string;
#ManyToOne(() => ResourceEntity, resource => resource.id)
resource: IResource;
}
When i query repository like this:
const userEntity = await this._userRepository.findOne({
where: {
username,
},
relations: ['role']
});
Your parent entity should not refer to an ID, you should have a relation to a field that defines your user entity.
like this :
UsersRoleEntity
#OneToMany(() => RolePermissionsEnitity, permission => permission.role)
permissions: IUserRolePermission[];
UsersEntity
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
You don't need to use JoinColumn() in ManyToOne and OneToMany relations.
You can find more information here:
TypeORM Relations Documentation
I have the following entities:
#Entity({ name: 'user' })
export class UserEntity extends BasicEntity {
#PrimaryGeneratedColumn()
id: number;
#Column({
nullable: false,
unique: true,
})
login: string;
}
#Entity({ name: 'wallet' })
export class WalletEntity extends BasicEntity {
#PrimaryGeneratedColumn()
id: number;
#ManyToOne(() => UserEntity)
#JoinColumn({ name: 'user_id' })
user: UserEntity;
#Column({
name: 'address',
type: 'text',
})
address: string;
}
So, the wallet table is looks like this:
-------------------------
id | user_id | address
-------------------------
1 | 1 | 0x12
-------------------------
2 | 43 | 0x10
And I like to update the wallet entity via Repository api. But the problem is, that I can't just:
WalletRepository.save({ address: '0x12', userId: 2 })
Because Typescript give me an error, that userId should be userEntity, but not number. But I want to update a relation column. So is there any option to update it?
I found an answer, not in TypeORM docs, but issues Github post.
So I need two columns:
#Entity({ name: 'wallet' })
export class WalletEntity extends BasicEntity {
#PrimaryGeneratedColumn()
id: number;
#ManyToOne(() => UserEntity, (entity: UserEntity) => entity.id)
#JoinColumn({ name: 'user_id' })
user: UserEntity;
#Column({ name: 'user_id', type: 'int' })
userId: number;
#Column({
name: 'address',
type: 'text',
})
address: string;
}
with {name: user_id} one is for relation, another is for relation update or find value. Which pretty unobvious. So if you want to search for a value by this relation ID, you could do it by the userID property of the Entity. But when you are doing join part, with relations[], you can access your object by user field.
Hi i have a relation between 'rooms' and 'room-servers'
RoomServers:
#Entity({ name: 'room-servers' })
export class RoomServer {
#PrimaryGeneratedColumn()
id: number;
#CreateDateColumn()
createdAt: Date;
#UpdateDateColumn()
updatedAt: Date;
}
Rooms:
#Entity({ name: 'rooms' })
export class Room {
#PrimaryGeneratedColumn()
id: number;
#Column({ default: '' })
name: string;
#Column({ nullable: true })
description: string;
#Column({ default: 'New' })
status: string;
#OneToOne(() => RoomServer, { nullable: false })
#JoinColumn()
roomServer: RoomServer;
}
When i type sql query
select * from "room-servers" rm left join rooms r on rm.id = r."roomServerId";
It returns results (3 servers that i have in database)
But when i try to use queryBuilder to see results:
const freeSocketServers = await this.roomServerRepository
.createQueryBuilder('room-servers')
.leftJoinAndSelect('room-servers.id', 'roomServerId')
.getMany();
console.log('freeSocketServer', freeSocketServers);
It returns nothing and i can't see console.log, it breaks on .leftJoinAndSelect
You set the relation in the room entity, To make it work you should go from room repository
const freeSocketServers = await this.roomRepository
.createQueryBuilder('room')
.leftJoinAndSelect('room.roomServer', 'room-server')
.getMany();
console.log('freeSocketServer', freeSocketServers);
Or you can make it Bi-directional see One-to-One