I'm new with ORM system and I'm trying to insert a data "Mark" binded with an object "pseudo".
This my entities,
Pseudo:
#Entity()
export class PseudoEntity{
#PrimaryGeneratedColumn()
id: number;
#Column({unique: true})
pseudo: string;
#Column({ default: 1 })
application_version: number;
#Column({ default: -1 })
score_on_last_calculation: number;
#Column({default: 1})
nb_request: number;
#Column({default: -1})
nb_mark_on_last_calculation: number;
#OneToMany(type => Mark, marks => marks)
marks: Mark[];
}
And Mark:
#Entity()
export class MarkEntity {
#PrimaryGeneratedColumn()
int: number;
#Column({ type: 'datetime'})
submission_date: Date;
#Column()
mark: number;
#ManyToOne(
type => Pseudo,
pseudo => pseudo,
)
pseudo: Pseudo;
}
This is my service to insert the data:
#Injectable()
export class MarkService {
constructor(private pseudoService: PseudoService) {}
async postMark(pseudo: string, mark: number) {
await this.pseudoService.findPseudo(pseudo).then(
p =>
getConnection()
.createQueryBuilder()
.insert()
.into(Mark)
.values([
{
mark: mark,
pseudo: p,
},
]),
);
}
}
I succeed to insert a Pseudo but not a mark :/
Could you help me please ?
Thanks in advance
First you should make a few slight changes to your entities:
#OneToMany(type => Mark, marks => marks.pseudo)
marks: Mark[];
#ManyToOne(
type => Pseudo,
pseudo => pseudo.marks,
)
pseudo: Pseudo;
Having made the changes above, use the injected pseudoRepository for querying and updating the desired Pseudo: (more about Registering and Injecting entities)
#Injectable()
export class MarkService {
constructor(#InjectRepository(Pseudo) private readonly pseudoRepository: Repository<Pseudo>) { }
async postMark(mark: number, pseudo: Pseudo): Promise<void> {
let _mark = new Mark();
mark.mark = mark;
mark.pseudo = await pseudoRepository.findOne({ pseudo });
await this.pseudoRepository.save(_mark)
}
}
I didn't try it but I suppose this should work:
import { Injectable } from '#nestjs/common';
import { PseudoEntity as Pseudo } from '../entity/pseudo.entity';
import { MarkEntity as Mark } from '../entity/mark.entity';
import { getConnection } from 'typeorm';
#Injectable()
export class PseudoService {
async postMark(markInput: number, pseudoInput: string) {
let mark = new Mark();
mark.mark = markInput;
mark.submission_date = Date.now();
mark.pseudo = await await repository.findOne({ pseudo: pseudoInput});
await getConnection().manager
.save(mark)
.then(mark => {
console.log("Mark has been saved. Mark id is ", mark.id);
});
}
//....
}
You should probably add a check in case no pseudo is found within the database for this pseudoInput.
Related
I have a typeorm entity that uses single table inheritance:
#Entity()
#TableInheritance({ column: { type: "varchar", name: "type" } })
#ObjectType({ isAbstract: false })
export class OrganisationEntity extends BaseEntity {
#Field()
#Column()
name: string;
#Field(() => [UserEntity])
#OneToMany(() => UserEntity, (user) => user.organisation)
users: UserEntity[];
}
and some child entities:
#ChildEntity()
#ObjectType()
class MedicalOrganisation {
}
#ChildEntity()
#ObjectType()
class SoftwareOrganisation {
}
#ChildEntity()
#ObjectType()
class MedicalOrganisation {
}
I'm wondering how I can get the type and the child properties from the parent organisation so that I can do something like:
const organisation = await OrganisationEntity.findOne()
if(organisation.type === "medicalOrganisation"){
...
}
But it seems I'm not allowed to access the type property through the parent. Does anyone know how this can be done?
I'd prefer not to use instanceof because it requires the child entities and is causing circular dependencies.
You've got two options. Either use .createQueryBuilder and get the item using getRawOne and the returned object would contain a field named OrganisationEntity_type which can be used to do the checks. It's value would either be 'MedicalOrganisation', or 'SoftwareOrganisation' and so on.
const orgRepository: Repository<OrganisationEntity> = getRepository(OrganisationEntity);
let organisation = await orgRepository.createQueryBuilder().getRawOne();
// organisation = {
// OrganisationEntity_name: 'name',
// OrganisationEntity_users: [
// {},
// {}
// ],
// OrganisationEntity_type: 'MedicalOrganisation'
// }
Or, you could add the field type in the OrganisationEntity itself like this:
#Entity()
#TableInheritance({ column: { type: "varchar", name: "type" } })
#ObjectType({ isAbstract: false })
export class OrganisationEntity extends BaseEntity {
#Field()
#Column()
name: string;
#Field(() => [UserEntity])
#OneToMany(() => UserEntity, (user) => user.organisation)
users: UserEntity[];
#Column
type: string;
}
and do a straightforward:
let organisation = await OrganisationEntity.findOne();
// organisation =
// MedicalOrganisation {
// name: 'name',
// users: [{}, {}],
// type: 'MedicalOrganisation'
// }
and you get the type field in the object itself.
I have an entity
#Column()
name: string;
#IsEmail()
email: string;
#Column({ select: false })
autogeneratedCode: string;
I'm getting name and string only in my GET request response which is expected.
But when I'm hit my POST Api with body, it is returning name, email, autogeneratedCode as well.
I need to hide autogeneratedCode in all CRUD responses.
Is there anyway to do that? or Am I missing something here?
You can use #Exclude() from 'class-transformer'
Example
import { Exclude } from 'class-transformer';
#Entity()
export class User {
#Column()
name: string;
#IsEmail()
email: string;
#Column({ select: false })
#Exclude()
autogeneratedCode: string;
constructor(entity: Partial<User>) {
Object.assign(this, entity);
}
}
Then you can use the constructor to create a new object excluding the #Exclude() properties.
export class UserService {
constructor(
#InjectRepository(User)
private userRepository: Repository<User>
) {}
public async createUser(user: User): Promise<User> {
return new User(
await this.userRepository.save(user)
);
}
}
NestJS Doc on Serialization
https://docs.nestjs.com/techniques/serialization#exclude-properties
I'm making Many to One, One to many relations with TypeORM and MySQL, and Express. There are two tables cold post and user.
One user has many posts. and each post has one user.
I would like to use 'userUuid' column as a foreign key to join these two tables.
Can anybody tell me how to fix it?
Thank you
// user
import {
Entity,
PrimaryGeneratedColumn,
Column,
BaseEntity,
BeforeInsert,
Generated,
OneToMany,
} from 'typeorm'
import { v4 as uuid } from 'uuid'
import { Post } from './Post'
#Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id!: number
#Column()
userId!: string
#Column()
#Generated('uuid')
userUuid!: string
#Column({ nullable: true })
displayName!: string
#Column({ nullable: true })
email!: string
#OneToMany(() => Post, (post: Post) => post.user)
posts!: Post[]
#BeforeInsert()
createUuid() {
this.userUuid = uuid()
}
toJSON() {
return { ...this, id: undefined }
}
}
// post
import {
Entity,
PrimaryGeneratedColumn,
CreateDateColumn,
UpdateDateColumn,
Column,
BaseEntity,
Generated,
BeforeInsert,
ManyToOne,
JoinColumn,
} from 'typeorm'
import { v4 as uuid } from 'uuid'
import { User } from './User'
#Entity()
export class Post extends BaseEntity {
#PrimaryGeneratedColumn()
id!: number
#Column()
#Generated('uuid')
postUuid!: string
#Column({ nullable: true })
userUuid!: string
#CreateDateColumn({ nullable: true })
createdAt!: Date
#UpdateDateColumn({ nullable: true })
updatedAt!: Date
#Column({ nullable: true })
content!: string
#BeforeInsert()
createUuid() {
this.postUuid = uuid()
}
#ManyToOne(() => User, (user: User) => user.posts)
user!: User
#JoinColumn([{ name: 'userUuid' }, { referencedColumnName: 'userUuid' }])
toJSON() {
return { ...this, id: undefined }
}
}
//express
router
.route('/')
.get((req: Request, res: Response) => {
User.find({ relations: ['posts'] })
.then((data) => {
res.send(data)
})
.catch((err) => res.send(err))
})
//express
router
.route('/')
.get((req: Request, res: Response) => {
Post.find({ relations: ['user'] })
.then((data) => {
res.send(data)
})
.catch((err) => res.send(err))
})
Seems like you need to use JoinColumn decorator.
class Post /*...*/ {
/*...*/
#ManyToOne(() => User)
#JoinColumn({ referencedColumnName: "userUuid" })
userUuid!: string;
/*...*/
}
From TypeORM docs
Join columns are always a reference to some other columns (using a foreign key). By default your relation always refers to the primary column of the related entity. If you want to create relation with other columns of the related entity - you can specify them in #JoinColumn as well:
#ManyToOne(type => Category)
#JoinColumn({ referencedColumnName: "name" })
category: Category;
The relation now refers to name of the Category entity, instead of id. Column name for that relation will become categoryName.
I am working on the backend of a project using Nestjs and everything has been okay until now that I found out an endpoint is giving an issue when I tested it on postman. Whenever I try to create using this endpoint, it gives this error: "TypeError: relatedEntities.forEach is not a function". I have tried my best to fix this but was not successful.
assessment entity
#Entity()
export class Result {
//...
#Column({ nullable: true })
summary: string;
#OneToMany(() => Assessment, (assessment) => assessment.result)
assessments: Assessment[];
//...
}
result entity
#Entity()
export class Assessment {
//...
#Column({ nullable: true })
format: string;
#ManyToOne(() => Result, (result) => result.assessments)
result: Result;
//...
}
result repository
#EntityRepository(Result)
export class ResultRepository extends Repository<Result> {
async createResult(createResultDto: CreateResultDto): Promise<Result> {
const { name, summary, assessments, comment } = createResultDto;
const result = new Result();
result.name = name;
result.assessments = assessments;
result.summary = summary;
result.comment = comment;
return this.save(result);
//more code...
In my nectjs project I'm using TypeORM and I have 2 entities user and post,
and I'm tying to make a relation between them
user.entity.ts
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column({ length: 50, unique: true })
name: string;
#OneToMany(type => Post, post => post.user)
posts: Post[];
}
post.entity.ts
#Entity()
export class Post {
#PrimaryGeneratedColumn()
id: number;
#Column({ length: 30 })
title: string;
#ManyToOne(type => User, user => user.posts)
user: User;
}
So I want to join these tables and get post by it's title for specific user
const PostObject = await createQueryBuilder("post")
.leftJoinAndSelect(
"post.user",
"user",
"post.title = :title",
{ title: "title1" }
)
.where("user.id = :id", { id: id })
.getOne();
but when I run the project and execute this function I get this error:
Error: "post" alias was not found. Maybe you forget to join it?
You have to inject the Repository first:
constructor(
#InjectRepository(Post) private readonly postRepository: Repository<Post>
) {
}
Then you can create the QueryBuilder for the Post entity by passing in the alias:
this.postRepository.createQueryBuilder('post')
// ^^^^^^^^^^^^^^^^
.leftJoinAndSelect(
'post.user',
'user',
'post.title = :title',
{ title: 'title1' },
)
.where('user.id = :id', { id })
.getOne();
Can also use getRepository like below.
const PostObject = await getRepository("post").createQueryBuilder("post")
.leftJoinAndSelect(
"post.user",
"user",
"post.title = :title",
{ title: "title1" }
)
.where("user.id = :id", { id: id })
.getOne();