Having a really strange issue with TypeORM and MariaDB. I have two entities with UUIDs as the primary key. The Companies entity is working fine as it scaffolds the schema as CHAR but the users table is being instantiated as an auto increment INT.
User Entity
#Entity()
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
firstname: string;
#Column()
lastname: string;
#Column({ unique: true })
email: string;
#Column()
password: string;
#ManyToOne(() => Company, (company) => company.users)
company: Company;
}
Companies Entity
#Entity()
export class Company {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
name: string;
#OneToMany(() => User, (user) => user.company)
users: User[];
}
Config
const config: MysqlConnectionOptions = {
type: 'mariadb',
....
entities: ['dist/src/**/*.entity.js'],
synchronize: true,
};
Users Table Screenshot
Companies Table Screenshot
Find it really strange, is it because I'm using MariaDB instead of straight MySQL?
Okay looks like I fixed it, really odd one. Looks like something was cached incorrectly. Deleted dist folder and node modules. reinstalled and total recompile. Fixed...
Related
I wanted to create one to one relation in typeorm (NestJS). Just like in the picture below.
I wanted then to signup user with email and password and create row in custom_auth and user_profile table.
relations
I cant find solution to create that type of relation. I was only able to create typical relation using foreign key (solution in typeorm docs)
export class CustomAuth {
#PrimaryGeneratedColumn()
id: number
#Column({ unique: true })
email: string
#Column()
password: string
#OneToOne(() => UserProfile, (userProfile) => userProfile.customAuth, {
cascade: true,
})
userProfile: UserProfile
}
export class UserProfile {
#PrimaryGeneratedColumn()
userId: number
#Column()
name: string
#Column({ nullable: true })
address: string
#OneToOne(() => CustomAuth, (customAuth) => customAuth.userProfile, {})
#JoinColumn()
customAuth: CustomAuth
}
Let's say we have a user entity already defined and it has 3 rows. We create another entity called Usage after sometime and add one-to-one relation with User. Is it possible to prefill the usage table having 3 rows related to user table with default values ?
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
username: string;
#Column()
password: string;
#OneToOne(() => Usage)
usage: Usage;}
#Entity()
export class Usage {
#PrimaryGeneratedColumn()
id: number;
#Column({default:0})
views: number;
#OneToOne(() => User)
#JoinColumn()
User: User; }
I try to delete user's profile when user was deleted. But it's delete nothing on profile.
User Entity
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#OneToOne(type => Profile, profile => profile.user,
{ eager: true, cascade: true, onDelete: 'CASCADE' })
#JoinColumn()
profile: Profile;
}
Profile Entity
#Entity()
export class Profile {
#PrimaryGeneratedColumn()
id: number;
#Column()
gender: string;
#Column()
photo: string;
#OneToOne(type => User, user => user.profile)
user: User;
}
How I delete a user.
const userRepository = connection.getRepository(User);
const user = await userRepository.findOne({ where: {id: 'someuserId'}, relations: ["profile"] });
await user.remove()
User was removed but nothing happen on user's profile.
Can anyone explain how to delete relationship on one-to-one?
User
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#OneToOne(type => Profile, profile => profile.user,
{ eager: true, onDelete: 'CASCADE' })
#JoinColumn()
profile: Profile;
}
Profile
#Entity()
export class Profile {
#PrimaryGeneratedColumn()
id: number;
#Column()
gender: string;
#Column()
photo: string;
#OneToOne(type => User, user => user.profile, { onDelete: "CASCADE" })
user: User;
}
I ran this code for removing entries from both the entities.
const userRepository = connection.getRepository(User);
const user = await userRepository.findOne({ where: {id: 'someuserId'} });
const profileRepository = connection.getRepository(Profile);
const profile = await profileRepository.findOne({ where: {id: user.profile.id} });
await profileRepository.remove(profile)
This is the expected behaviour for one-to-one relation. You have to delete referencing side to take cascade deletion to take in effect. discussion link
edit: raised issue on github
Solution
I recently found myself in the same spot. I created a inheritance relationship in my database. Multiple entities reference one common entity which provides basic attributes for each specialized table. For example: Common attribute holder table "Car" and specialized tables "Truck", "Bus". Now I wanted to delete the corresponding "Car"-entity whenever a "Truck" or "Bus" is deleted.
In typeorm the specialized tables should reference the common attribute table. To make the CASCADE DELETE work, you have to specify the side which holds the id using the #JoinColumn() annotation. Then you have to specify the onDelete: "CASCADE" on the One-to-One relationship of the same side as the #JoinColumn() annotation.
To validate the created table you can use SHOW CREATE TABLE table_name in your database. There you will see if the CASCADE DELETE is present on the correct foreign key constraint. (It should be on the table holding the foreign key).
That means, it is not required to set the CASCADE DELETE on both sides.
Code example
(see Gaurav Sharma's answer - modified)
// referenced table
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
// you can use eager on the none-owning side
// this can be very helpful for inheritance
#OneToOne(type => Profile, profile => profile.user, { eager: true })
profile: Profile;
}
// owning side - foreign key in this table
#Entity()
export class Profile {
#PrimaryGeneratedColumn()
id: number;
#Column()
gender: string;
#Column()
photo: string;
// specify onDelete here because owning side FK constraint would fail
// and it needs to know what is going to happen
#OneToOne(type => User, user => user.profile, { onDelete: "CASCADE" })
#JoinColumn()
user: User;
}
From here on you would create a new user. Set the saved user in the profile to save and save the profile.
Deleting the profile will not delete the user.
Deleting the user will delete the profile.
I also looked into CASCADE DELETE from both sides. From what I have found, you would have to specify the #JoinColumn() annotation on both sides, declaring onDelete: "CASCADE" on both sides. This will require at least two saves for new entities and I did not find further information in the docs concerning the bidirectional CASCADE DELETE. I would consider deleting manually in these situations because it might become very unclear what is going to happen and when entities need to be saved.
I solved my problem (for now)
I just manual remove in both entities.
const userRepository = connection.getRepository(User);
const user = await userRepository.findOne({ where: {id: 'someuserId'}, relations: ["profile"] });
const profileRepository = connection.getRepository(Profile);
const profile = await profileRepository.findOne({where: {id: user.profile.id}}).getOne()
await profile.remove()
await user.remove()
I'm new to TypeORM and databases overall and I have simple question.
What is the way to 'merge' entities?
For example:
I have two entities, Product and Producer:
#Entity()
export class Product {
#PrimaryGeneratedColumn()
id: number;
#Column("int")
producer_id: number;
#Column()
producer: //I want show producer data here
#Column("varchar", { length: 255 })
name: string;
}
#Entity()
export class Producer {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
logo: string;
}
As you can see, in Product entity I have producer_id property which contains ID of producer.
When I'm loading the product I want TypeORM to search through producers, get one with Id matching producer_id in Product and store it in producer property.
Maybe my question is little bit embroiled but I hope you'll get the point.
Thanks for all answers.
As far as I can see, you're looking for a one-to-many relation (one producer many products).
Check this doc from typeorm for further info. But basically do the following:
#Entity()
export class Product {
#PrimaryGeneratedColumn()
id: number;
#Column("int")
producer_id: number;
#ManyToOne(type => Producer, producer => producer.product)
producer: Producer
#Column("varchar", { length: 255 })
name: string;
}
#Entity()
export class Producer {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
logo: string;
#OneToMany(type => Product, product => product.producer)
products: Product[]
}
And then in your queries specify relations to fetch:
productRepository.find({ relations: ["producer"] });
I'm not an user of typeorm, but it should be something like that
In this case, the store can have many owners, and the owners can have many store.
However, when i save the entity by using Repository and the problem happen:
Maximum call stack size exceeded
I think it need to use Nested Tree annotation? But i dont know how to correct it. Please help!
#Entity('store')
export class StoreEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
name: string;
...
#ManyToMany(type => UserEntity, user => user.ownStores)
#JoinTable()
owners: UserEntity[];
}
#Entity('user')
export class UserEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({
type: 'varchar',
})
email: string;
...
#ManyToMany(type => StoreEntity, store => store.owners)
ownStores: StoreEntity[];