We were working on Multi tenant architecture at Nest using TypeOrm. Cannot find public entity when referencing public schema in tenenat schema
Error:
TypeORMError: Entity metadata for UserDetail#countryId was not found. Check if you specified a correct entity object and if it's connected in the connection options.
Schema in tenent:
Entity: userDetail
#ManyToOne(() => Country, (country) => country.userDetails, {
nullable: true,
onDelete: 'SET NULL',
})
#JoinColumn({ name: 'country_id' })
countryId?: Country;
Public:
Entity: countries
#OneToMany(() => UserDetail, (userDetail) => userDetail.countryId)
userDetails?: UserDetail[];
How can I refer to the public table?
Related
That's the updateEntity.ts
import { IsNotEmpty } from 'class-validator'
import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
import { Company } from './company.entity'
#Entity('countries')
export class Country extends BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string
#IsNotEmpty()
#Column({ unique: true })
name: string
#ManyToOne(() => Company, (company) => company.locations, { nullable: true })
#JoinColumn({ name: 'company_id' })
countryId: Company[]
}
CompanyEntity.ts with the location field
#OneToMany(() => Country, (country) => country.countryId, { eager: true })
locations: Array<Country>
and here is the function where I want to update the properties
async update(id: number, updateCompanyDto: UpdateCompanyDto) {
const newLocations = updateCompanyDto.locations.map((location) => Country.create(location))
updateCompanyDto.locations = newLocations
const status = await Company.update(id, updateCompanyDto)
if (status.affected <= 0) {
throw new HttpException('This company does not exist', HttpStatus.NOT_FOUND)
}
return status
}
First time working with OneToMany and ManyToMany, and if I have the request body like this
"locations": [{"name":"Paris"}]
I'm getting an error "Cannot query across one-to-many for property locations"
I just want to be able to update the companies
It's okay because if you need to update,create or delete data from Location entity,you need to query using that entity not from joined entity
I'm writing because I have a question while dealing with the mapping table. When creating a user on a web page, I want to put existing information and data called equipment. Each user can start with multiple equipment, so they created a mapping table like a picture to resolve the N:M relationship.
However, in order to put data in the mapping table in typeorm, you must first create a user object and an item object. After turning the loop as many times as the number of equipment set to the user to find the equipment number received from the web, we are creating an equipment object and inserting it into the mapping table.
Is there a better way than what I'm doing?
await Promise.all(
items.map(async (element) => {
const uItem = new UserItem();
uItem.item = element.item;
uItem.user = user;
uItem.period = element.period;
await transactionManager.save(uItem);
})
);
typeORM has an easy solution for it
So you define your 2 main entities like this
#Entity()
export class Item{
#PrimaryGeneratedColumn('uuid')
id: string; // or whatever you like
#OneToMany(() => UserItems, userItem => userItem.item, {
nullable: true,
cascade: true,
})
userItems: UserItem[];
...
#Entity()
export class User{
#PrimaryGeneratedColumn('uuid')
id: string; // or whatever you like
#OneToMany(() => UserItems, userItem => userItem.user, {
nullable: true,
cascade: true,
})
userItems: UserItem[];
...
And your mapping class as following:
#Entity()
export class UserItem{
#PrimaryGeneratedColumn('uuid')
id: string; // or whatever you like
#ManyToOne(() => User, {
onDelete: 'CASCADE', // decide on delete logic
})
user: User;
#ManyToOne(() => Item, {
onDelete: 'CASCADE', // decide on delete logic
})
item: Item;
...
I'm currently implementing an M:M relationship between a user and a product that uses a custom join table for implementing a shopping cart. Here is the custom join table:
#Entity({ tableName: "users_in_cart_products" })
export class UserInCartProducts {
#ManyToOne(() => User, { primary: true, nullable: true })
user: User;
#ManyToOne(() => Product, { primary: true, nullable: true })
product: Product;
#Property()
amount: number;
}
Parts of the user entity (similar to Product)
#Entity({ tableName: "users", customRepository: () => UserRepository })
export class User {
#PrimaryKey()
id: string = v4();
/* some properties */
#OneToMany(() => UserInCartProducts, (userInCartProducts) => userInCartProducts.user)
userInCartProducts = new Collection<UserInCartProducts>(this);
}
I'm currently implementing a functionality where a product will be deleted from the shopping cart. However, when I call user.userInCartProducts.remove(), instead of just removing that element, it removes everything from user.userInCartProducts, leaving an empty array. Here's the code that removes the product from a user's cart:
async removeCartItem(userId: string, productId: string) {
const user = await this.userRepository.findOneOrFail({ id: userId }, [
"userInCartProducts",
"userInCartProducts.product",
]);
for (const e of user.userInCartProducts) {
if (e.product.id === productId) user.userInCartProducts.remove(e);
}
await this.userRepository.persistAndFlush(user);
return user;
}
I've checked the SQL generated from Mikro-orm, and somehow it sets user_id to NULL for everything inside the users_in_cart_products join table:
[query] update "users_in_cart_products" set "user_id" = NULL [took 2808 ms]
So how can I solve this problem? I just want the collection to remove that one item, but not every single item. Thanks!
And still managing to do #OneToMany in another entity.
export class ProductsOfOrder {
#ManyToOne(() => Order, order => order.products)
order: Order
#ManyToOne(() => Product)
product: Product
#Column({type: 'integer'})
amount: number
}
In the case using the foreign key of order
#Entity()
export class Order {
#PrimaryGeneratedColumn('uuid')
id: string
#ManyToOne(() => User)
user: User
#OneToMany(() => ProductsOfOrder, productsOfOrder => productsOfOrder.order, {cascade: true})
products: ProductsOfOrder[]
}
Ciao, no you can't because its required for entities to have a primary column in terms of ORM because most of ORM operations are heavily rely on entity primary ids.
When implementing User entity and Roles entity in TypeORM, I used #ManyToMany with eager on true.
I implemented a UserRepository that extends Repository.
When using this.find() it works, without a problem (but also loads the password and other fields an API doesn't need to serve). When using this.find({select: 'email firstname roles'}), it suddenly gives me this error:
RequestError: Invalid column name 'userId'.
I also tried adding option relations, but that gives me error
QueryFailedError: Error: Invalid column name 'userId'.
Can anyone help me with this?
Node version: 12.16.2
TypeORM version: 0.2.24
Typescript version: 3.7.4
Database: SQL Server
Role entity:
#Entity()
export class Role {
#ManyToMany(type => User, user => user.roles)
#PrimaryColumn()
role!: string
}
User Entity
#Entity()
export class User {
#PrimaryGeneratedColumn()
id!: number;
#Column()
public email!: string;
#Column()
public password!: string;
#Column()
public firstname!: string;
#ManyToMany(type => Role, role => role.role, {eager: true, nullable: true})
#JoinTable()
public roles!: Role[];
}
User Repository:
#EntityRepository(User)
export class UserRepository extends Repository<User> {
whitelist: IWhitelist<User> = {
admin: ['email', 'firstname','roles', 'id',]
};
getOptions = (list: string) => {
return {select: this.whitelist[list], relations: ['roles']};
};
adminGetUsers = async (): Promise<Array<User> | undefined> => {
return await this.find(this.getOptions('admin'));
};
}
Have you tried
this.find({select: ['email', 'firstname', 'roles']}
from the documentation :
https://github.com/typeorm/typeorm/blob/master/docs/find-options.md#basic-options