TypeORM update with join table (One-To-Many, Many-To-One) - mysql

There are two example entities.
#Entity('companies')
export class Company {
#PrimaryColumn({ name: 'id' })
id: string;
#Column({ name: 'name' })
name: string;
#OneToMany(() => employee, (employee) => employee.company)
#JoinColumn({ name: 'id', referencedColumnName: 'company_id' })
employees: Employee[];
}
#Entity('employees')
export class Employee {
#PrimaryColumn({ name: 'id' })
id: string;
#Column({ name: 'name' })
name: string;
#ManyToOne(() => company, (employee) => company.employees, { eagar: true, cascade: true} )
#JoinColumn({ name: 'company_id', referencedColumnName: 'id' })
company: Company;
}
And I prepared the entity as follows for the update. (It can update my company's information or my employees' information.)
const employee = new Employee();
employee.id = 'employee1';
employee.name = 'mike';
const companyEntity = await companyRepository.findByEmployeeId(employee_id);
companyEntity.name = 'stackoverflow';
companyEntity.employees = [employee];
await companyRepository.save(companyEntity);
If save like this, an error occurs because TypeORM processes as follows. (It wasn't an exact error. It was a similar error.)
// (Before the update, All users with 'company1' company have been inquired.)
query: SELECT employee.id FROM employee WHERE employee.company_id = 'company1'
query: UPDATE employee SET company_id = NULL WHERE employee.id = 'employee2'
query: UPDATE employee SET company_id = NULL WHERE employee.id = 'employee3'
query failed: Column 'company_id' cannot be NULL
In the end, it seems to be an error caused by all users belonging to the company trying to be inquired and updated.
What should I do to update the employees using the save method?

Check your employee.entitiy file, I think you may have the relationship not quite right:
// company.entity.ts
#Entity('companies')
export class Company {
#PrimaryColumn({ name: 'id' })
id: string;
#Column({ name: 'name' })
name: string;
#OneToMany(() => Employee, (employee) => employee.company)
employees: Employee[];
}
// employee.entity.ts
#Entity('employees')
export class Employee {
#PrimaryColumn({ name: 'id' })
id: string;
#Column({ name: 'name' })
name: string;
#ManyToOne(() => Company, (company) => company.employees)
#JoinColumn({
name: 'company_id',
})
company: Company;
}
Personally, when updating a record, I'll do something like this—using your employee as an example:
// employee.service.ts
async updateEmployee(
employeeId: string,
updateEmployeeDto: UpdateEmployeeDto,
): Promise<Employee> {
/**
* This will stop the show and return a 404 if the employee cannot be found.
*/
const employee = await this.getEmployeeById(employeeId);
const { name } = updateEmployeeDto;
employee.name = name;
try {
await employee.save();
} catch (err) {
throw new InternalServerErrorException(err.message);
}
return employee;
}
Or, if I am doing a create it might look something like this:
// employee.service.ts
async createEmployee(createEmployeeDto: CreateEmployeeDto): Promise<Employee> {
return await this.employeeRepository.createEmployee(createEmployeeDto);
}
// employee.repository.ts
async createUser(createEmployeeDto: CreateEmployeeDto): Promise<Employee> {
const { name } = createEmployeeDto;
const employee = this.create();
employee.name = name;
try {
await employee.save();
} catch (err) {
throw new InternalServerErrorException(err.message);
}
return employee;
}

Related

Using SUM function with subqueries Typeorm

I want to build these query with queryBuilder i have tried it but giving error
MYSQL QUERY -
select sum(total), count(invoiceId)
from(
select sum(price) as 'total', invoiceId from items
group by items.invoiceId
)
as ie;
I have written these in typeorm but not working
const data = await this.itemsRepo
.createQueryBuilder('items')
.select('sum(price)', 'total')
.groupBy('invoiceId')
.getQuery();
return await this.itemsRepo
.createQueryBuilder()
.select('COUNT(ie.total)', 't')
.from(`${data}`, 'ie')
.getRawMany();
showing these error
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '` FROM `items` `items` GROUP BY invoiceId` `ie`' at line 1
& genrated query by typeorm is
SELECT sum(price) AS total FROM items items GROUP BY invoiceId
items entity
#Entity()
export class Items {
#PrimaryGeneratedColumn()
id: number;
#Column()
item: string;
#Column()
hsn: number;
#Column()
qty: number;
#Column()
material: number;
#Column()
price: number;
#Column()
invoiceId: number;
#ManyToOne(() => Invoices, (invoice) => invoice.items)
#JoinColumn({ name: 'invoiceId' })
invoice: Invoices;
}
Invoice Entity
#Entity()
export class Invoices {
#PrimaryGeneratedColumn()
id: number;
#Column()
challanNo: string;
#Column()
transportaion: number;
#Column()
clientId: number;
#ManyToOne(() => Client, (client) => client.invoices)
#JoinColumn({ name: 'clientId' })
client: Client;
#OneToMany(() => Items, (item) => item.invoice)
items: Array<Items>;
#CreateDateColumn({
type: 'timestamp',
default: () => 'CURRENT_TIMESTAMP(6)',
})
created_at: Date;
}

How to join 3 relation table using typeorm nestjs

I am using typeorm with NestJs, I try to join 3 relations but got an error path comment.user in entity was not found
Here is my table User
Id
username
1
row
#PrimaryGeneratedColumn()
id: number;
#Column()
username: string;
#OneToMany(() => PostEntity, (post) => post.user, { eager: true })
posts: PostEntity[];
Here is my table Posts
Id
desc
user_id
1
text
1
#PrimaryGeneratedColumn()
id: number;
#Column()
desc: string;
#Column()
userId: number;
#ManyToOne(() => User, (user) => user.posts, {
eager: false,
onDelete: 'CASCADE',
})
user: User[];
#OneToMany(() => CommentEntity, (comment: CommentEntity) => comment.post, {
eager: true,
onDelete: 'CASCADE',
})
comment: CommentEntity[];
Here is my table comment
Id
comment
user_id
postId
1
comment post 1
1
1
#PrimaryGeneratedColumn()
id: number;
#Column()
comment: string;
#Column()
userId: number;
#Column()
postId: number;
#ManyToOne(() => PostEntity, () => (post: PostEntity) => post.comment, {
eager: false,
onDelete: 'CASCADE',
})
post: PostEntity[];
#OneToOne(() => User)
#JoinColumn()
user: User;
In here I use OneToOne because 1 comment can comment by only 1 user
this is what my data look like
```
this.createQueryBuilder('post')
.leftJoinAndSelect('post.user', 'user')
.leftJoinAndSelect('post.comment', 'comment')
.select(['post', 'user.id', 'user.username', 'comment'])
.getMany();
```
this is what I get
[
{
id: 1,
description: 'comment post 1',
userId: 1,
user: {
id: 1,
username: 'row',
},
comment: [
{
id: 1,
description: 'comment',
userId: 1,
postId: 1,
},
],
},
];
In comment I want to join userId for user that comment . I want data look like this
[
{
id: 1,
description: 'comment post 1',
userId: 1,
user: {
id: 1,
username: 'row',
},
comment: [
{
id: 1,
description: 'comment',
userId: 1,
postId: 1,
user: {
// if different user comment will show different username
id: 1,
username: 'row',
},
},
],
},
];
This is what I try to do
this.createQueryBuilder('post')
.leftJoinAndSelect('post.user', 'user')
.leftJoinAndSelect('post.comment', 'comment')
.leftJoinAndSelect('post.comment.user', 'user')
.select(['post', 'user.id', 'user.username', 'comment'])
.orderBy('post.updated_at', 'DESC')
.getMany();
.leftJoinAndSelect('post.comment.user', 'user') // In this line I want to join userId but Its show an error path comment.user in entity was not found
UPDATE
I try to use this ( this mean PostEntity)
this.find({ relations: ['user', 'comment', 'comment.user']
but still not working
Update your Comment entity's user relationship like this:
#OneToOne(() => User)
#JoinColumn({name: 'userId'})
user: User;
Then try:
this.createQueryBuilder('post')
.leftJoinAndSelect('post.user', 'user')
.leftJoinAndSelect('post.comment', 'comment')
.leftJoinAndSelect('comment.user', 'commentedUser')
.select(['post', 'user.id', 'user.username', 'comment', 'commentedUser'])
.orderBy('post.updated_at', 'DESC')
.getMany();

TypeORM inserts an additional empty row for no reason when saving an entity

I've been making an application for tracking user finances with NestJS, TypeORM and MySQL on the backend and all was going swell until I ran into a brick wall which was saving an entity called Financialchange which represents one unit of financial expense or gain. The problem is that in a table that represents a many to many relationship of user defined tags with the financial change, an empty row is inserted every time I save this entity along with the row that is correctly inserted.
The saving is done like this:
const financialChange = await this.financialChangeRepository.save({
amount: payload.amount,
description: payload.description,
expense: payload.expense,
paymentSourceId: payload.paymentSourceId,
appUserId: payload.appUserId,
createdAt: format(new Date(), "yyyy-MM-dd hh:mm:ss")
});
payload.tagIds.forEach(async (tagId) => {
await this.financialChangeTagRepository.save({
financialChangeId: financialChange.id,
tagId
});
});
An example of sent data:
mutation {
addFinancialChange(
financialChange: {
appUserId: 1
amount: 200
description: "Description"
expense: true
paymentSourceId: 1
tagIds: [1]
}
)
}
And when selecting data from the many to many table I get this:
The entity data is as follows, first the MySQL table creation:
CREATE TABLE financialchange (
id INT AUTO_INCREMENT PRIMARY KEY,
amount DOUBLE,
createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
description VARCHAR(255),
expense BOOLEAN,
paymentSourceId INT,
appUserId INT,
FOREIGN KEY (appUserId) REFERENCES appuser(id),
FOREIGN KEY (paymentSourceId) REFERENCES paymentsource(id)
);
And then the TypeORM entity in Nest:
#Index("appUserId", ["appUserId"], {})
#Index("paymentSourceId", ["paymentSourceId"], {})
#Entity("financialchange", { schema: "finapp" })
export class Financialchange {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("double", { name: "amount", nullable: true, precision: 22 })
public amount?: number | null;
#Column("datetime", { name: "createdAt", default: () => "CURRENT_TIMESTAMP" })
public createdAt?: Date;
#Column("varchar", { name: "description", nullable: true, length: 255 })
public description?: string | null;
#Column("tinyint", { name: "expense", nullable: true, width: 1 })
public expense?: boolean | null;
#Column("int", { name: "paymentSourceId", nullable: true })
public paymentSourceId?: number | null;
#Column("int", { name: "appUserId", nullable: true })
public appUserId?: number | null;
#ManyToOne(() => Appuser, (appuser) => appuser.financialchanges, {
onDelete: "NO ACTION",
onUpdate: "NO ACTION"
})
#JoinColumn([{ name: "appUserId", referencedColumnName: "id" }])
public appUser?: Appuser;
#ManyToOne(
() => Paymentsource,
(paymentsource) => paymentsource.financialchanges,
{ onDelete: "NO ACTION", onUpdate: "NO ACTION" }
)
#JoinColumn([{ name: "paymentSourceId", referencedColumnName: "id" }])
public paymentSource?: Paymentsource;
#OneToMany(
() => Financialchangetag,
(financialchangetag) => financialchangetag.financialChange
)
public financialchangetags?: Financialchangetag[];
}
It is in concept defined as having N amounts of tags binded to it, which is why I have created a table that represents a many to many relation called financialchangetags:
CREATE TABLE financialchangetag (
id INT AUTO_INCREMENT PRIMARY KEY,
financialChangeId INT,
tagId INT,
FOREIGN KEY (financialChangeId) REFERENCES financialchange(id),
FOREIGN KEY (tagId) REFERENCES tag(id)
);
#Index("financialChangeId", ["financialChangeId"], {})
#Index("tagId", ["tagId"], {})
#Entity("financialchangetag", { schema: "finapp" })
export class Financialchangetag {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("int", { name: "financialChangeId", nullable: true })
public financialChangeId?: number | null;
#Column("int", { name: "tagId", nullable: true })
public tagId?: number | null;
#ManyToOne(
() => Financialchange,
(financialchange) => financialchange.financialchangetags,
{ onDelete: "NO ACTION", onUpdate: "NO ACTION" }
)
#JoinColumn([{ name: "financialChangeId", referencedColumnName: "id" }])
public financialChange?: Financialchange;
#ManyToOne(() => Tag, (tag) => tag.financialchangetags, {
onDelete: "NO ACTION",
onUpdate: "NO ACTION"
})
#JoinColumn([{ name: "tagId", referencedColumnName: "id" }])
public tag?: Tag;
}
And the tag table is defined in this manner:
CREATE TABLE tag (
id INT AUTO_INCREMENT PRIMARY KEY,
description VARCHAR(255)
);
#Entity("tag", { schema: "finapp" })
export class Tag {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("varchar", { name: "description", nullable: true, length: 255 })
public description?: string | null;
#OneToMany(
() => Financialchangetag,
(financialchangetag) => financialchangetag.tag
)
public financialchangetags?: Financialchangetag[];
}
I have no clue why this is, I have tried inserting a record into financialchange with a transaction manager and through other methods of saving data that TypeORM offers, but I still get an empty row in my M:N table.

UnhandledPromiseRejectionWarning: Error: Entity metadata for Category#products was not found

I looked at other issues that throw the same error, but none of then worked for me. I tried rename, import, put in config file, I read the typeorm doc a thousand times but I can't find the solution. Can anyone help me?
On ormconfig.json:
"entities": [
"./src/models/*.ts"
],
Category entity:
import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import Product from './Product';
import User from './User';
#Entity('categories')
class Category {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column('varchar')
name: string;
#Column('varchar')
description?: string;
#ManyToOne(() => User, categories => Category)
#JoinColumn()
user: User;
#OneToMany(() => Product, product => product.category)
products: Product[];
}
export default Category;
Product entity:
import { PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import Category from './Category';
import Model from './Model';
import Provider from './Provider';
import User from './User';
export enum Genre {
FEMALE = 'F',
MALE = 'M',
}
export enum Size {
PP = 'PP',
P = 'P',
M = 'M',
G = 'G',
GG = 'GG',
SIZE_33 = '33',
SIZE_34 = '34',
SIZE_35 = '35',
SIZE_36 = '36',
SIZE_37 = '37',
SIZE_38 = '38',
SIZE_39 = '39',
SIZE_40 = '40',
SIZE_41 = '41',
SIZE_42 = '42',
SIZE_43 = '43',
SIZE_44 = '44',
SIZE_45 = '45',
SIZE_46 = '46',
SIZE_47 = '47',
SIZE_48 = '48',
SIZE_49 = '49',
SIZE_50 = '50',
SIZE_51 = '51',
SIZE_52 = '52',
}
export enum Status {
IN_STOCK = 'I',
OUTPUT = 'O',
}
enum Purchase_type {
CONSIGNED = 'C',
OWNER = 'O',
}
class Product {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column('varchar')
name: string;
#Column('enum')
genre: Genre;
#Column('varchar')
color: string;
#Column('enum')
size: Size;
#Column('enum')
status: Status;
#Column('datetime')
created_at: Date;
#Column('varchar')
id_photo?: string;
#Column('varchar')
obs?: string;
#Column('float')
sale_value: number;
#Column('float')
purchase_value: number;
#Column('enum')
purchase_type: Purchase_type;
#Column('varchar')
brand: string;
#ManyToOne(() => User, user => user.products)
#JoinColumn()
user: User;
#ManyToOne(() => Provider, provider => provider.products)
#JoinColumn()
provider: Provider;
#ManyToOne(() => Category, category => category.products)
category: Category;
#ManyToOne(() => Model, model => model.products)
#JoinColumn()
model: Model;
}
export default Product;
The error:
(node:10691) UnhandledPromiseRejectionWarning: Error: Entity metadata for Category#products was not found. Check if you specified a correct entity object and if it's connected in the connection options.
at /home/guilherme/Documentos/Restore/src/metadata-builder/EntityMetadataBuilder.ts:664:23
at Array.forEach ()
at EntityMetadataBuilder.computeInverseProperties (/home/guilherme/Documentos/Restore/src/metadata-builder/EntityMetadataBuilder.ts:659:34)
at /home/guilherme/Documentos/Restore/src/metadata-builder/EntityMetadataBuilder.ts:118:56
at Array.forEach ()
at EntityMetadataBuilder.build (/home/guilherme/Documentos/Restore/src/metadata-builder/EntityMetadataBuilder.ts:118:25)
at ConnectionMetadataBuilder.buildEntityMetadatas (/home/guilherme/Documentos/Restore/src/connection/ConnectionMetadataBuilder.ts:66:111)
at Connection.buildMetadatas (/home/guilherme/Documentos/Restore/src/connection/Connection.ts:517:59)
at Connection. (/home/guilherme/Documentos/Restore/src/connection/Connection.ts:193:18)
at step (/home/guilherme/Documentos/Restore/node_modules/tslib/tslib.js:141:27)
You seems you forgot Entity for product entity
import { PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Entity } from 'typeorm';
import Category from './Category';
import Model from './Model';
import Provider from './Provider';
import User from './User';
#Entity('products') // you forget this
class Product {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column('varchar')
name: string;
#Column('enum')
genre: Genre;
#Column('varchar')
color: string;
#Column('enum')
size: Size;
#Column('enum')
status: Status;
#Column('datetime')
created_at: Date;
#Column('varchar')
id_photo?: string;
#Column('varchar')
obs?: string;
#Column('float')
sale_value: number;
#Column('float')
purchase_value: number;
#Column('enum')
purchase_type: Purchase_type;
#Column('varchar')
brand: string;
#ManyToOne(() => User, user => user.products)
#JoinColumn()
user: User;
#ManyToOne(() => Provider, provider => provider.products)
#JoinColumn()
provider: Provider;
#ManyToOne(() => Category, category => category.products)
category: Category;
#ManyToOne(() => Model, model => model.products)
#JoinColumn()
model: Model;
}
export default Product;

how to get a parent ID in child entity object in typeorm + nestjs

I have a simple relation company has many projects and everything is super fine, when I get the result parent ID is missing from entity object while its present in query
Company Entity :
#Entity()
export class Company {
#PrimaryGeneratedColumn({ unsigned: true })
id: number;
#Column({ nullable: false })
name: string;
#Column({
type: 'datetime',
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
})
created_at;
#Column({ nullable: true, type: 'datetime' })
updated_at;
#OneToMany(
type => Project,
project => project.company
)
project: Project[];
}
Project Entity :
#Entity()
export class Project {
#PrimaryGeneratedColumn({ unsigned: true })
id: number;
#Column({ nullable: false })
name: string;
#ManyToOne(
type => Company,
company => company.project,
{ nullable: false }
)
#JoinColumn({ name: 'company_id' })
company: Company;
#Column({
type: 'datetime',
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
})
created_at;
#Column({ nullable: true, type: 'datetime' })
updated_at;
}
Query in service :
return this.companyRepository.find({ where: { id: 1 }, relations: ['project'] })
Query log is :
SELECT
`Company`.`id` AS `Company_id`,
`Company`.`name` AS `Company_name`,
`Company`.`created_at` AS `Company_created_at`,
`Company`.`updated_at` AS `Company_updated_at`,
`Company__project`.`id` AS `Company__project_id`,
`Company__project`.`name` AS `Company__project_name`,
`Company__project`.`created_at` AS `Company__project_created_at`,
`Company__project`.`updated_at` AS `Company__project_updated_at`,
`Company__project`.`company_id` AS `Company__project_company_id`
FROM
`company` `Company`
LEFT JOIN
`project` `Company__project` ON `Company__project`.`company_id` = `Company`.`id`
WHERE
`Company`.`id` = 1;
but when i print result my company object contains project array but in project array company_id is missing or typeorm has excluded it while creating an object, is there any way than i can get parent_id which is company_id in project object
Result :
Company {
id: 1,
name: 'company',
created_at: 2020-10-24T18:46:59.000Z,
updated_at: null,
project: [
Project {
id: 1,
name: 'project 1',
created_at: 2020-10-24T18:47:35.000Z,
updated_at: null
},
Project {
id: 2,
name: 'project 2',
created_at: 2020-10-24T19:08:08.000Z,
updated_at: null
}
]
}
expected result :
Company {
id: 1,
name: 'company',
created_at: 2020-10-24T18:46:59.000Z,
updated_at: null,
project: [
Project {
id: 1,
company_id: 1, <========= this is required
name: 'project 1',
created_at: 2020-10-24T18:47:35.000Z,
updated_at: null
},
Project {
id: 2,
company_id: 1,
name: 'project 1',
created_at: 2020-10-24T19:08:08.000Z,
updated_at: null
}
]
}
In the fireld 'company_id' you are not supposed to get the id field of company, as it is the company object itself. So from that object you may get its id. I think that if you would set 'eager: true' on the field, you will get the object in the query, because the default is eager: false.
If what you want is only the id and not the whole object, maube think of a field which is a foreign key to the company id using one-to-one relation, which will give you your wanted reault output
I think you should be able to split that up like this. companyId will automatically be extracted from company.
// ...
#ManyToOne(type => Company, company => company.project)
company: Company;
#Column({nullable: true})
companyId: number;
// ...