I'm working with Nest.js, TypeORM, and PostgreSQL, I have two entities(product and stone) with a many to many relation, based on my own business project, I have to add one extra column to that many to many table(product_stone), but I have some issue with my solution, at first I try to create a product with a set of stones:
"stones": [
{"id": 1,"count":1},
{"id": 2,"count": 3}
]
and after that, I try to add the count to the product_stone table by updating it, the result will be like this:
product_stone_table
till here everything is Okay, but every time that I restart the server all of the data in that extra column will be set to its default value(null):
product_stone_table
And also I tried to do not set the count to {nullable:true} in product_stone table and add count during the creation of a product, but when I want to restart the server I receive an error kile this:
QueryFailedError: column "count" of relation "product_stone" contains null values
Is there anybody to guide me?
product.entity.ts
#Entity()
export class Product extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#ManyToMany(() => Stone)
#JoinTable({
name: 'product_stone',
joinColumn: {
name: 'productId',
referencedColumnName: 'id',
},
inverseJoinColumn: {
name: 'stoneId',
referencedColumnName: 'id',
},
})
stones: Stone[];
}
stone.entity.ts
#Entity()
export class Stone extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
}
product_stone.entity.ts
#Entity('product_stone')
export class ProductStone extends BaseEntity {
#Column({ nullable: true })
count: number;
#Column()
#IsNotEmpty()
#PrimaryColumn()
productId: number;
#Column()
#IsNotEmpty()
#PrimaryColumn()
stoneId: number;
}
I don't think you can define custom attributes on many-to-many table like that.
From documentation:
In case you need to have additional properties in your many-to-many relationship, you have to create a new entity yourself
In your case that would mean you would have to so something like that:
// product_stone.entity.ts
#Entity()
export class ProductToStone {
#PrimaryGeneratedColumn()
public id: number;
#Column()
public productId: number;
#Column()
public stoneId: number;
#Column()
public count: number;
#ManyToOne(() => Product, product => product.productToStone)
public product: Product;
#ManyToOne(() => Stone, stone => stone.productToStone)
public stone: Stone;
}
// product.entity.ts
...
#OneToMany(() => ProductToStone, productToStone => postToCategory.product)
public productToStone!: PostToCategory[];
// stone.entity.ts
...
#OneToMany(() => ProductToStone, postToCategory => postToCategory.stone)
public postToCategories!: PostToCategory[];
Related
I have two entities, Teacher and Student with a many to many relationship, connected using a join table called TeacherStudents. I want to query multiple teachers and the related students under each teacher, but i want to be able to limit how many teachers are fetched per query and also limit how many related students are fetched per teacher.
My entities:
Teacher.ts
#Entity()
export class Teacher extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
#OneToMany(() => TeacherStudents, (ts) => ts.teacher)
studentConn: Promise<TeacherStudents[]>;
}
Student.ts
#Entity()
export class Student extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
#OneToMany(() => TeacherStudents, (ts) => ts.student)
teacherConn: Promise<TeacherStudents[]>;
}
Then I have a separate join table to connect both entities
TeacherStudents.ts
#Entity()
export class TeacherStudents {
#PrimaryColumn()
teacherId: number;
#PrimaryColumn()
studentId: number;
#ManyToOne(() => Teacher, (teacher) => teacher.studentConn)
#JoinColumn({ name: 'teacherId' })
teacher: Promise<Teacher>;
#ManyToOne(() => Student, (student) => student.teacherConn)
#JoinColumn({ name: 'studentId' })
student: Promise<Student>;
}
So far I have been able to get this working
query.ts
async getTeachers(limit:number){
const maxLimit = Math.min(16, limit)
const teachers = await AppDataSource.getRepository(Teacher)
.createQueryBuilder('teacher')
.innerJoin('teacher.studentConn', 'studentConn')
.innerJoin('studentConn.student', 'student')
.select('teacher', 'student')
.take(maxLimit)
.getMany();
return teachers;
}
The issue with this is that "take" only applies on the parent (Teacher) object. I want to know how I can apply "take" on the child (Student) for each Teacher returned by the query.
Basically I want to paginate for each Teacher and it's relation Student.
I'm using TypeORM with Postgresql and having trouble creating entity file with nested scheme
The records I would like returned from my database should look like this:
[{
id: 1,
name: 'john'
preferences: {
colors: ['red', 'white', '#ff5d5d'],
cars: ['vw', 'bmw']
}
}]
Im having trouble with the preferences property.
this is what I tried:
#Entity()
export class Person {
#PrimaryGeneratedColumn()
id: string;
#Column()
name: string;
preferences: {
#OneToMany(() => Color, c => c)
colors: Color[]
#OneToMany(() => Car, c => c)
cars: Car[]
}
}
#Entity()
export class Color {
#PrimaryGeneratedColumn()
id: string;
#Column()
value: string;
}
#Entity()
export class Car {
#PrimaryGeneratedColumn()
id: string;
#Column()
value: string;
}
This does not compile because i cant put the OneToMany decorator in a nested property and
also I don't need id for the colors nor the cars.
I only use id because I need it mapped per person.
Consider a base entity as below:
export abstract class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
and two child entities as below:
#Entity()
export class NotificationType1 extends Notification {}
and
#Entity()
export class NotificationType2 extends Notification {}
Is there a way to find all rows in NotificationType1 and NotificationType2 using a query to the parent class like this?
SELECT * FROM NOTIFICATION;
This query return 0 rows, although there are records in NotificationType1 and NotificationType2 tables.
You should be able to Select from the superclass and retrieve all the records with something like this:
import {getConnection} from "typeorm";
const user = await getConnection().createQueryBuilder()
.select("notification")
.from(Notification, "notification");
You also need to change your abstract class to #TableInheritance to leverage Single Table Inheritance.
This Code:
export abstract class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
Would become:
#Entity()
#TableInheritance({ column: { type: "varchar", name: "type" } })
export class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
And the Child Entity:
#ChildEntity()
export class NotificationType1 extends Notification {}
The docs have on single table inheritance.
How do I define a relationship?
#Entity('favoritesable')
export class FavoritesEntity extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
favoritesableId: number; // foreing key ( ads id, blog id, user id )
#Column()
favoritesableType: string; // ads, blog, user
#Column()
userId: number;
}
ads entity:
#Entity('ads')
export class AdsEntity extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
// How do I define a relationship to FavoritesEntity ?
}
data example for favoritesable table :
{id: 1, favoritesableId: 1, favoritesableType: "ads", userId: 1},
{id: 2, favoritesableId: 4, favoritesableType: "ads", userId: 1},
{id: 3, favoritesableId: 1, favoritesableType: "ads", userId: 2},
how to make this relation on ads entity and favorites Entity ?
TypeORM's documentation pretty clearly shows ow to make a relationship between entities.
Example pulled from their docs:
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany} from "typeorm";
import {Question} from "./Question";
#Entity()
export class Category {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#ManyToMany(type => Question, question => question.categories)
questions: Question[];
}
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm";
import {Category} from "./Category";
#Entity()
export class Question {
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
#Column()
text: string;
#ManyToMany(type => Category, category => category.questions)
#JoinTable()
categories: Category[];
}
I'm using TypeORM in Node.JS and would like to use the entity inheritance to implement a BaseRecord:
export abstract class BaseRecord {
#CreateDateColumn({type: 'timestamp'})
public created_at: Date;
#UpdateDateColumn({type: 'timestamp'})
public updated_at: Date;
#ManyToOne(type => User, user => user.records_created)
public created_by: User
#ManyToOne(type => User, user => user.records_updated)
public updated_by: User
}
Which I would like to extend other entities by. This works as expected when removing the #ManyToOne relationship:
#Entity()
export class Address extends BaseRecord {
#PrimaryGeneratedColumn()
public id: number;
#Column({ nullable: true, type: "text" })
public alias: string;
#Column({ type: "text" })
public street_1: string;
#Column({ nullable: true, type: "text" })
public street_2: string;
#Column({ type: "text" })
public city: string;
#Column({ type: "text" })
public state: string;
#Column({ type: "text" })
public zip_code: string;
#Column(type => GeoLocation)
public geo_location: GeoLocation
}
Has anyone run into this or a method to inherit entity and have ManyToOne relationships?
I suggest using composition over inheritance with an Embedded Entity
An embedded column is a column which accepts a class with its own columns and merges those columns into the current entity's database table.
You can use as many columns (or relations) in embedded classes as you need. You even can have nested embedded columns inside embedded classes.
import {Column} from "typeorm";
export class Assigned {
#ManyToOne(type => User, user => user.records_created)
public created_by: User
#ManyToOne(type => User, user => user.records_updated)
public updated_by: User
}
export class Dated {
#CreateDateColumn({type: 'timestamp'})
public created_at: Date;
#UpdateDateColumn({type: 'timestamp'})
public updated_at: Date;
}
then use it
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import {Assigned} from "./Assigned";
import {Dated} from "./Dated";
#Entity()
export class Address extends BaseRecord {
// ...Other columns
#Column(type => Assigned)
assigned: Assigned;
#Column(type => Dated)
dated: Dated;
}
You can use as many columns (or relations) in embedded classes as you need.
You even can have nested embedded columns inside embedded classes.