I have this model:
#Entity()
export class Trade extends BaseEntity {
...
#OneToOne(() => Fee, { cascade: true })
#JoinColumn()
fee: Fee;
...
}
#Entity()
export class Fee extends BaseEntity {
...
#OneToOne(() => Trade, trade => trade.fee)
trade!: Trade
...
}
I'm trying to get the equivalent of:
await getManager().find(Trade, { relations: ['fee'] })
with the QueryBuilder.
await createQueryBuilder('trade')
.leftJoinAndSelect(Fee, 'fee', 'fee.tradeId = trade.feeTradeId')
.getMany()
await getManager().find(Trade, { relations: ['fee'] })
My problem: when I use getManager().find(...) the fee property gets populated with the relation, however, when using the QueryBuilder it is not (trade.fee is undefined).
How can I get fee populated using a left join with the query builder?
The syntax is incorrect:
await createQueryBuilder('trade')
.leftJoinAndSelect('trade.fee', 'fee', 'fee.tradeId = trade.feeTradeId')
.getMany()
you may get the data without mentioning the condition
await createQueryBuilder('trade')
.leftJoinAndSelect('trade.fee', 'fee')
.getMany()
here's a question explaining the syntax: Explain typeorm join syntax
Related
I read and searched a lot but did not find any solution to my problem. I read this, this, ...
My database is MySQL. There is no problem with one-to-many and many-to-many. in one-to-one relation
// Student.ts(Parent)
#Entity({ name: "student" })
export class StudentEntity {
#PrimaryGeneratedColumn()
public id: number;
#Column({ nullable: true })
public name: string;
#OneToOne(() => StudentProfile, (profile) => profile.student, { onDelete: "CASCADE", cascade: ['insert', 'update'] })
public profile: StudentProfile
}
// Profile.ts
#Entity({ name: "profile" })
export class StudentProfile {
#PrimaryGeneratedColumn()
id: number
#Column({ nullable: true })
username: string
#OneToOne(() => StudentEntity, (student) => student.profile, { onDelete: "CASCADE" })
public student: StudentEntity
}
Now, With The following code I want to remove the student and their profile:
const student = await this._studentRepository.findOne({ where: { id: 4 } })
await this._studentRepository.delete(student)
The code above does not work. there is another way: I can remove the student and profile individually, I do not want to do this.
any help would be appreciated. Thanks in advance.
As the stackoverflow you included, mentions: You have to delete referencing side to take cascade deletion to take in effect.
I guess you've to delete like:
const student = await this._studentRepository.findOne({ where: { id: 4 } })
const profile = await this._profileRepository.findOne({ where: { id: student.profile } }) // if you don't have an eager relationship
await this._profileRepository.delete(profile)
or in case of an eager relationship between student and profile:
const student = await this._studentRepository.findOne({ where: { id: 4 } })
await this._profileRepository.delete(student.profile) // if you've an eager relationship
I have a few Entities Action, and GPKAsset
In the ActionSubscriber.ts I would like to perform certain things based on the contract column as you can see below.
The problem I am encountering is on await actionManager.addRelationAccount(action); it is throwing exceptions saying that the record doesn't exist in actions. This is quite confusing because I have the id of the action and this is the afterInsert event.
I am guessing either I am doing something wrong or it's some sort of race condition, or it's a bug?
Any guidance would be greatly appreciated.
Thank you
Action.ts
export class Action extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
REMOVED COLUMNS AND OTHER RELATIONSHIPS TO REDUCE CLUTTER
#ManyToMany(() => GPKAsset, gpkAsset => gpkAsset.actions)
gpkAssets: GPKAsset[];
GPKAsset.ts
export class GPKAsset extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Index()
#Column()
contract: string;
REMOVED COLUMNS AND OTHER RELATIONSHIPS TO REDUCE CLUTTER
#ManyToMany(() => Action, action => action.gpkAssets)
#JoinTable({name:'gpkassets_actions'})
actions: Action[];
ActionSubscriber.ts
#EventSubscriber()
export class ActionSubscriber implements EntitySubscriberInterface<Action> {
listenTo() {
return Action;
}
async afterInsert(event: InsertEvent<Action>): Promise<Promise<any> | void> {
let action: Action = event.entity;
switch (event.entity.contract) {
case 'simpleassets:createlog':
let gpkAsset: GPKAsset | null = new GPKAsset();
gpkAsset = await gpkassetManager.createGPKAssetFromAction(action);
await actionManager.addRelationAccount(action);
if (gpkAsset !== null) {
await actionManager.addRelationGPKAsset(action, gpkAsset))
}
break;
case 'simpleassets:transfer':
await gpkassetManager.transferGPKAssetOwnership(action);
break;
default:
}
}
}
I'm setting up a server using TypeORM + PostgreSQL. When saving saving my entity to the entity's repository, I receive the error: TypeError: relatedEntities.forEach is not a function and the entity is not saved to the database.
This seems to only happen when I am using the #OneToMany or #TreeChildren decorators.
Here is my entity class that is causing the problem:
import { ServiceData } from './service-data.entity';
import { ManufacturerData } from './manufacturer-data.entity';
import { Entity, Column, PrimaryGeneratedColumn, TreeChildren } from 'typeorm';
#Entity()
export class Advertisement {
#PrimaryGeneratedColumn()
id: number;
#Column({ nullable: true })
name?: string;
#Column()
gatewayId: string;
#Column()
rssi: number;
#Column({ nullable: true })
mac?: string;
#TreeChildren()
manufacturerData?: ManufacturerData[];
#TreeChildren()
serviceData?: ServiceData;
}
The (abbreviated) error output is:
UnhandledPromiseRejectionWarning: TypeError: relatedEntities.forEach is not a function
at OneToManySubjectBuilder.buildForSubjectRelation (/<project-directory>/src/persistence/subject-builder/OneToManySubjectBuilder.ts:78:25)
Found the problem.
#TreeChildren and #OneToMany always expect an array. I had to change serviceData?: ServiceData; to serviceData?: ServiceData[];
This error can come up when the oneTomany relationships are not properly written in the Entity design and also when you trying to store the relationships in a table.
The first One is, setting the Entity holding many of the other Entity like this
#OneToMany(() => Address, (address) => address.users)
address: Address[];
The other entity that has manyToOne relationship like this,
#ManyToOne(() => Users, (users) => users.address)
users: Users;
If the relationships are all good, then the problem is storing the entity relations to the database.
when creating the user, store the relationships like this
address = await this.addressRepository.findOneOrFail({
where: {
user_id: Number(userId),
},
});
const user = new User();
user.name = name;
user.age = age;
### store the address as an array of objects to the relationship column
users.address = [address]
I have an Entity Transaction and an Entity Integration
#Entity()
export default class Transaction {
#PrimaryGeneratedColumn()
public id_trans?: number;
#OneToOne(type => Integration, i => i.transaction, { nullable: true })
public integration?: Integration;
}
and
#Entity()
export default class Integration {
#PrimaryGeneratedColumn()
public id_cust?: number;
#OneToOne(type => Transaction, t => t.integration)
#JoinColumn({ referencedColumnName: 'id_trans', name: 'int_id_module' })
public transaction?: Transaction;
}
I tried to query the Transaction by using a Integration property as filter.
const id_api = 10;
const transaction = await repository.find({
where: { integration: { int_id_api: id_api} },
relations: ['integration', 'customer'],
});
but it returns the entire table of Transactions, even if the integration.int_id_api is different from id_api property
What am I doing wrong. What should I do to get this query working ?
You need to add a primary key to all your entities. From the doc:
Each entity must have at least one primary key column. This is a
requirement and you can't avoid it. To make a column a primary key,
you need to use #PrimaryColumn decorator.
Assuming you update the Integration entity like so
#Entity()
export default class Integration {
#PrimaryColumn()
public id_inte: number;
#OneToOne(type => Transaction, t => t.integration)
#JoinColumn({ referencedColumnName: 'id_trans', name: 'int_id_module' })
public transaction?: Transaction;
}
You should be able to find transactions like so
const transaction = await repository.find({
where: { integration: { id_inte: some_id } },
relations: ['integration', 'customer'],
});
Is their any possibility to use mongoDB ObjectID system with MySql and typeORM instead of using an incremental ID?
The goal would be to define my entity like this:
#Entity()
export class RolePermission implements IRolePermission {
#ObjectIdColumn() id?: ObjectID;
#Column()
#IsNotEmpty()
roleId: ObjectID;
#Column()
#IsNotEmpty()
permissionId: ObjectID;
}
My entities could therefore have an ID without even being persisted. The ObjectId system would prevent collisions on the unique constraint I'd like to use for this column.
If a system like that can be implemented, is their any performance downside? I remember implementing such a system with PHP, and at the time, I had read this response that made me think that it was ok: Is there a REAL performance difference between INT and VARCHAR primary keys?
It's in fact really simple. You just need to use the ObjectID object from the mongodb package and declare your entities like you would do usually.
First, install mongodb dependencies:
yarn add mongodb
yarn add #types/mongodb
Then, declare your entity. Here an example with a working relationship between a user and an article:
user.entity.ts:
import { Entity, Column, ManyToOne, PrimaryColumn } from 'typeorm';
import { Article } from './article.entity';
import { ObjectID } from 'mongodb';
#Entity()
export class User {
constructor() {
this.id = (new ObjectID()).toString();
}
#PrimaryColumn()
id: string;
#Column({ length: 500 })
username: string = null;
#OneToMany(type => Article, article => article.user)
articles: Article[];
}
article.entity.ts:
import { Entity, Column, ManyToOne, PrimaryColumn } from 'typeorm';
import { User } from './user.entity';
import { ObjectID } from 'mongodb';
#Entity()
export class Article {
constructor() {
this.id = (new ObjectID()).toString();
}
#PrimaryColumn()
id: string;
#Column({ length: 500 })
title: string = null;
#ManyToOne(type => User, user => user.articles, {nullable: true})
user: User;
}
And use it as you would normally do:
const user = new User();
user.username = 'email#adress.com';
const article = new Article();
article.title = 'Mon titre';
article.user = user;
await this.userRepository.save(user);
await this.articleRepository.save(article);