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;
// ...
Related
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;
}
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;
}
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();
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.
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;