Duplicate column name with TypeORM in Nestjs - mysql

We have 2 entities: EstateIntegrationEntity and EstateEntity
When we try to use .findOne on the estateIntegrationRepository we get the following error:
[Nest] 5537 - 10/01/2020, 8:37:55 AM
[ExceptionsHandler] ER_DUP_FIELDNAME: Duplicate column name 'EstateIntegrationEntity_estate_id' +1590ms
QueryFailedError: ER_DUP_FIELDNAME: Duplicate column name 'EstateIntegrationEntity_estate_id'
at ...
We created a OneToOne relation from the EstateIntegrationEntity to the EstateEntity.
import { EstateEntity } from "src/estates/estate.entity";
import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, RelationId } from "typeorm";
#Entity({ name: 'estate_integrations' })
export class EstateIntegrationEntity {
#PrimaryGeneratedColumn()
id: number;
#RelationId((estateIntegrationEntity: EstateIntegrationEntity) => estateIntegrationEntity.estate)
estate_id: number;
#OneToOne(() => EstateEntity, { eager: true })
#JoinColumn({ name: 'estate_id' })
estate: EstateEntity;
...
}
And a relation from the EstateEntity to the EstateIntegrationEntity :
import { EstateIntegrationEntity } from 'src/integrations/estate.integration.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
#Entity('estates')
export class EstateEntity {
#PrimaryGeneratedColumn()
id: number;
#Column('varchar' || null)
uuid: string;
#OneToOne(
() => EstateIntegrationEntity,
estate_integration => estate_integration.estate,
)
estate_integration: EstateIntegrationEntity;
}
This error only occurs with .findOne() and not with .find():
async findEstateById(id: string): Promise<EstateIntegrationEntity> {
return await this.estateIntegrationRepository.findOne({
where: {
external_id: id
}
});
}

You can change the name of the fields. I just had a similar error and fixed it changing the name with #Column({ name: 'name_the_fields_with_different_name' }). Because the problem that if in the tables it has the same name when it does the find it has to fields with the same name.

For this case you have 3 solution for this:
1- change column name from 'estate_id' to anything else like 'id_estate'
2- write custom join statement with TypeORM
3- my favorite solution is to use name strategy like this:
first install npm i --save typeorm-naming-strategies
then in your typeorm config file
const SnakeNamingStrategy = require('typeorm-naming-strategies')
.SnakeNamingStrategy;
module.exports = {
name: 'name',
type: 'mysql',
host: 'localhost',
port: 3306,
...
namingStrategy: new SnakeNamingStrategy(),
}

Related

Problem NestJS/TypeORM : [Nest] 3100 ERROR [ExceptionHandler] Nest can't resolve dependencies of the ProjetslaboService (?)

After having followed the following tutorial in full:
https://www.youtube.com/watch?v=JK5aynTxKjM&list=PL4bT56Uw3S4zIAOX1ddx8oJS6jaD43vZC
I decided to do my crud based on this:
I tested TypeORM with my category (Categorie), so just a simple table with no foreign key or anything and it worked like a charm and the program runs CRUD.
I said so I decided to make several tables including the "ProjectsLabo" table, with two foreign keys.
But problem when I incorporate in my module the three other modules I have an error:
[Nest] 3100 - 25/01/2023, 14:39:29 ERROR [ExceptionHandler] Nest can't resolve dependencies of the ProjetslaboService (?). Please make sure that the argument ProjetslaboDtoRepository at index [0] is available in the ProjetslaboMo
dule context.
Potential solutions:
Is ProjetslaboModule a valid NestJS module?
If ProjetslaboDtoRepository is a provider, is it part of the current ProjetslaboModule?
If ProjetslaboDtoRepository is exported from a separate #Module, is that module imported within ProjetslaboModule?
#Module({
imports: [ /* the Module containing ProjetslaboDtoRepository */ ]
})
Error: Nest can't resolve dependencies of the ProjetslaboService (?). Please make sure that the argument ProjetslaboDtoRepository at index [0] is available in the ProjetslaboModule context.
Potential solutions:
Is ProjetslaboModule a valid NestJS module?
If ProjetslaboDtoRepository is a provider, is it part of the current ProjetslaboModule?
If ProjetslaboDtoRepository is exported from a separate #Module, is that module imported within ProjetslaboModule?
#Module({
imports: [ /* the Module containing ProjetslaboDtoRepository */ ]
})
Here is an example of the LaboProjects module :
projetslabo.dto.ts
import { IsNotBlank } from "../../decorators/is-not-blank.decorator";
export class ProjetslaboDto {
//#IsString()
//#IsNotEmpty()
#IsNotBlank({message : 'Serveur : the name is not empty'})
nom?: string;
}
projetslabo.controller.ts
#Controller('projetslabo')
export class ProjetslaboController {
constructor(private readonly projetslaboService: ProjetslaboService) {
}
#Get()
async GetAll() {
return await this.projetslaboService.getAll();
}
#Get(':id')
async GetOne(#Param('id', ParseIntPipe) id: number) {
return await this.projetslaboService.findById(id);
}
}
projetslabo.entity.ts
#Entity({ name: 'projetslabo' })
export class ProjetslaboEntity {
#PrimaryGeneratedColumn()
idProjetsLabo: number;
#Column({ type: 'varchar', length: 40, nullable: false })
nom: string;
#ManyToOne(() => ValeurslaboEntity, (ValeurslaboEntity) => ValeurslaboEntity.idValeursLabo , {nullable : false})
FK_idValeursLabo: ValeurslaboEntity
#ManyToOne(() => AnneeslaboEntity, (AnneeslaboEntity) => AnneeslaboEntity.idAnneesLabo, {nullable : false})
FK_idAnneesLabo: AnneeslaboEntity
}
Projetslabo.module.ts
#Module({
imports: [TypeOrmModule.forFeature([ProjetslaboEntity])],
providers: [ProjetslaboService],
controllers: [ProjetslaboController],
})
export class ProjetslaboModule {}
projetslabo.repository.ts
#EntityRepository(ProjetslaboEntity)
export class ProjetslaboRepository extends Repository<ProjetslaboEntity>{}
projetslabo.service.ts
#Injectable()
export class ProjetslaboService {
constructor(
#InjectRepository(ProjetslaboDto)
private projetslaboRepository: ProjetslaboRepository,){}
async getAll(): Promise<ProjetslaboEntity[]> {
const list = await this.projetslaboRepository.find();
if (!list.length) {
throw new NotFoundException(
new MessageDto('Serveur : La liste est vide'),
);
}
return list;
}
async findById(idProjetsLabo: number): Promise<ProjetslaboEntity> {
const annees = await this.projetslaboRepository.findOneBy({
idProjetsLabo,
});
if (!annees) {
throw new NotFoundException(
new MessageDto("Serveur : Cette année n'existe pas"),
);
}
return annees;
}
app.module.ts
#Module({
imports: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
type: 'mariadb',
host: configService.get<string>(DB_HOST),
port: +configService.get<number>(DB_PORT),
username: configService.get<string>(DB_USER),
password: configService.get<string>(DB_PASSWORD),
database: configService.get<string>(DB_DATABASE),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
logging: true,
}),
inject: [ConfigService],
}),
CategoriesModule,
/*Problem with this 3 modules
ProjetslaboModule,
ValeurslaboModule,
AnneeslaboModule,
*/
],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
Can you help me please?
Nestjs/core : 9.0.0
Nestjs/typeorm : 9.0.1
You pass ProjetslaboDto to your #InjectRepository() when you should be passing ProjetslaboEntity as that's what you've told TypeOrmModule.forFeature() about.
#Injectable()
export class ProjetslaboService {
constructor(
- #InjectRepository(ProjetslaboDto)
+ #InjectRepository(ProjetslaboEntity)
private projetslaboRepository: ProjetslaboRepository,){}
...

Typeorm typescript repository findone - Argument of type is not assignable to parameter of type 'FindOneOptions<GuildConfiguration>'

Here is my configuration file.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#Entity({ name: 'guild_configurations' })
export class GuildConfiguration {
#PrimaryGeneratedColumn()
id: number;
#Column({ unique: true, name: 'guild_id' })
guildId: string;
#Column({ default: '?' })
prefix: string;
#Column({ name: 'welcome_channel_id', nullable: true })
welcomeChannelId: string;
}
I was trying to add search guildId with discord guild.id
// https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=e-guildCreate
import { Guild } from 'discord.js';
import BaseEvent from '../utils/structures/BaseEvent';
import DiscordClient from '../client/client';
import { getRepository, ObjectID } from 'typeorm';
import { GuildConfiguration } from '../typeorm/entities/GuildConfiguration';
export default class GuildCreateEvent extends BaseEvent {
constructor(
private readonly guildConfigRepository = getRepository(GuildConfiguration)
) {
super('guildCreate');
}
async run(client: DiscordClient, guild: Guild) {
console.log("Hello World");
console.log(`Joined ${guild.name}`);
const config = await this.guildConfigRepository.findOne({guildId:guild.id});
if(config){
console.log("A configuration was found!")
}else{
console.log("Configuration was not found. Creating one...")
const newConfig = this.guildConfigRepository.create({guildId:guild.id})
return this.guildConfigRepository.save(newConfig);
}
}
}
this.guildConfigRepository.findOne({guildId:guild.id});
it shows
Argument of type '{ guildId: string; }' is not assignable to parameter of type 'FindOneOptions'.
Object literal may only specify known properties, and 'guildId' does not exist in type 'FindOneOptions'.ts(2345)
my typeorm version is "typeorm": "^0.3.1"
Does anyone know how to fix this?
Thanks!
You can use the where key instead such as:
this.guildConfigRepository.findOne({
where: {
guildId: guild.id
}
});
As you're using the 0.3.x typeorm you might use the findOneBy instead of findOne.
const config = await this.guildConfigRepository.findOneBy({guildId:guild.id});
I just downgraded my typeorm version from 0.3.x to 0.2.41 and it worked!

Problem saving ManyToMany relation in MySQL database via microservices

I have a relationship created between User and Groups, where a group can contain multiple users and a user can be present in more than one group. The relationship was built on the UserEntity and GroupsEntity entities. The problem occurs when the request is made in Postman. The User record is created, but the ids corresponding to the relationship between groups and user are not created in the new table (relationship of the two entities).
Help codes:
UserEntitity.ts
import { AssociateEntity } from 'src/associate/entities/associate.entity';
import { Associate } from 'src/associate/interfaces/associate.interface';
import { GroupsEntity } from 'src/groups/entities/group.entity';
import { Groups } from 'src/groups/interfaces/groups.interface';
import { SubsidiaryEntity } from 'src/subsidiary/entities/subsidiary.entity';
import { Subsidiary } from 'src/subsidiary/interfaces/subsidiary.interface';
import {
Column,
DeleteDateColumn,
Entity,
JoinTable,
ManyToMany,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
#Entity()
export class UserEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
login: string;
#Column()
password: string;
#Column()
email: string;
#Column()
adm: boolean;
#Column()
passwordValidity: string;
#Column()
initials: string;
#Column()
system: string;
#ManyToOne(() => SubsidiaryEntity, (subsidiary) => subsidiary.id)
subsidiary: Subsidiary;
#ManyToMany(() => GroupsEntity, { cascade: true })
#JoinTable()
group: Groups[];
#Column({ default: true })
status: boolean;
#DeleteDateColumn()
deletedAt: Date;
#OneToMany(() => AssociateEntity, (associate) => associate.id)
associate: Associate[];
}
GroupsEntity.ts
import { UserEntity } from 'src/user/entities/user.entity';
import { User } from 'src/user/interfaces/user.interface';
import {
Column,
DeleteDateColumn,
Entity,
ManyToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
#Entity()
export class GroupsEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
description: string;
#Column({ default: true })
status: boolean;
#DeleteDateColumn()
deletedAt: Date;
#ManyToMany(() => UserEntity, (user) => user.group)
user: User;
}
user.service.ts (method create)
async create(user: User) {
try {
const groups: Array<Groups> = await this.groupService.findByIds(
user.groups,
);
//#ts-ignore
user.groups = groups;
const newUser = await this.userRepository.save(user);
return newUser;
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error.message)}`);
throw new RpcException(error.code + error.message);
}
}
The structure of the bank is given by:
Bank entity relationships
The code doesn't report errors, but it doesn't create the relationship with the ids either. I'm using microservices in nestJS, the language is TypeScript and the database used is MySQL.
Join table you have define the join Column and inverseJoinColumn Details. Example
#JoinTable({
name: 'cat_use_cloth',
joinColumn: { name: 'cat_id', referencedColumnName: 'id'},
inverseJoinColumn: { name: 'cloth_id', referencedColumnName: 'id'},
})
Ref: https://medium.com/#rodrigo.tornaciole/nest-js-many-to-many-relationship-using-typeorm-and-crud-ec6ed79274f0

NestJs update Many-To-Many relation with join table

I have two entities - Property and Owner. One Property can have a lot of Owners and Owner can have a lot of Properties. For join use property_owner table. How to update this many-to-many relation using NestJS/TypeORM?
#Entity('property')
export class Property extends EntityModel {
#Column({ length: 255, nullable: false })
name: string;
#ManyToMany(type => Owner, { cascade: true })
#JoinTable({
name: 'property_owner',
joinColumn: { name: 'propertyId', referencedColumnName: 'id'},
inverseJoinColumn: { name: 'ownerId', referencedColumnName: 'id'},
})
owners: Owner[];
}
#Entity('owner')
export class Owner extends EntityModel {
#Column({ length: 255, nullable: false })
name: string;
#ManyToMany(type => Property, { cascade: true })
#JoinTable({
name: 'property_owner',
joinColumn: { name: 'ownerId', referencedColumnName: 'id'},
inverseJoinColumn: { name: 'propertyId', referencedColumnName: 'id'},
})
properties: Property[];
}
Below my service's methods for save and update:
public create(req: Request): Promise<Dto> {
const dto: CreateDto = {
...req.body,
owners: this.formatJoinData(req.body.owners) //[1,2,3] => [{id:1},{id:2},{id:3}]
};
const entity = Object.assign(new Entity(), dto);
return this.repo.save(entity);
}
public update(req: Request): Promise<UpdateResult> {
const dto: EditDto = {
...req.body,
owners: this.formatJoinData(req.body.owners) //[1,2,3] => [{id:1},{id:2},{id:3}]
};
const id = req.params.id;
const entity = Object.assign(new Entity(), dto);
return this.repo.update(id, entity);
}
Saving new Property work fine, but when I try update property I get error
[ExceptionsHandler] column "propertyId" of relation "property" does not exist
Owners data in both cases looks like [{id:1},{id:2},{id:3}]. I think problem in save/update methods results. Save method return to us Entity with id and update method return to us UpdateResult which not contain Entity id. But may be we can transform/additionally define this value somewhere...
I found solution. Need to call save method instead update.
In my case update will be looks like
import {plainToClass} from 'class-transformer';
public async update(req: Request): Promise<Dto> {
const found = await this.repo.findOneOrFail(req.params.id, {
relations: ['owners', 'electricMeter'],
});
const dto = {
...found,
...req.body,
owners: this.formatJoinData(req.body.owners) //[1,2,3] => [{id:1},{id:2},{id:3}]
updatedBy: this.getUser(req),
updatedDate: Date.now(),
};
return this.repo.save(plainToClass(Entity, dto));
}
This code can be improved, but think that main idea is clear.
https://typeorm.io/#/many-to-many-relations documentation doesn't say more than use JoinTable decorator, and we don't know what you havr in your request, but it looks like you're passing wrong values. These fields are virtual, at the end with m2m relationship third table is created to handle relationship.

Typeorm how to get relations of relations

I am getting the Object ChatRoomEntity with entitymanager.findOne method. The ChatRoomEntity has the variable messages which is a OneToMany - ManyToOne Relation. I have no problems to select that but how do I get the user which sent the message. Its a variable on MessageEntity with a OneToMany Relation.
So basically I want to select a room and all messages of it. But all messages should also have their values on fromUser.
I select the room like this:
this.entityManager.findOne(ChatRoomEntity, {where: {id: roomToJoin.id}, relations: ['activeUsers', 'messages']}).then(roomEntity => {
// some code
}
Here my entities:
UserEntity
#Entity()
export class UserEntity {
#PrimaryGeneratedColumn()
id: number;
#CreateDateColumn()
registrationDate: Date;
#ManyToMany(type => ChatRoomEntity, room => room.activeUsers, {cascade: true})
#JoinTable()
activeChatRooms: ChatRoomEntity[];
#OneToMany(type => ChatRoomMessageEntity, msg => msg.fromUser)
chatRoomMessages: ChatRoomMessageEntity[];
}
ChatRoomEntity
#Entity()
export class ChatRoomEntity {
#PrimaryGeneratedColumn()
id: number;
#Column('varchar', {nullable: true})
title: string;
#OneToMany(type => ChatRoomMessageEntity, chatrmsg => chatrmsg.chatRoom)
messages: ChatRoomMessageEntity[];
#ManyToMany(type => UserEntity, user => user.activeChatRooms)
activeUsers: UserEntity[];
}
ChatRoomMessageEntity
#Entity()
export class ChatRoomMessageEntity {
#PrimaryGeneratedColumn()
id: number;
#Column('varchar', {nullable: true})
message: string;
#CreateDateColumn()
creationDate: Date;
#ManyToOne(type => UserEntity, user => user.chatRoomMessages)
fromUser: UserEntity;
#ManyToOne(type => ChatRoomEntity, chatRoom => chatRoom.messages)
chatRoom: ChatRoomEntity;
}
We can load sub-relations by using 'relation.subrelation' within the relations array itself like this:
relations: ['relation1', 'relation2', 'relation2.subrelation1']
So for your case, instead of using join you can simply do something like this:
this.entityManager.findOne(ChatRoomEntity, {
where: {id: roomToJoin.id},
relations: ['activeUsers', 'messages', 'messages.fromUser'],
}).then(roomEntity => {
...
This is specified here: https://github.com/typeorm/typeorm/blob/master/docs/find-options.md#basic-options
Using QueryBuilder
await getRepository(UserEntity)
.createQueryBuilder('user')
.leftJoinAndSelect('user.profile', 'profile')
.leftJoinAndSelect('profile.images', 'images')
.getMany()
Using FindOptions
await getRepository(UserEntity).find({
relations: ['profile', 'profile.images']
})
Update v0.4.0
Typeorm is ditching findOne, you should use findOneBy for the queries without relations, and if you want relations, simply use find.
const users = await userRepository.find({
where: { /* conditions */ },
relations: { /* relations */ }
})
// users[0] if you want a first row
here is the #gradii/fedaco orm how to implement this feature.
use can use multi relations by method with
export class User extends Model {
#HasOneColumn({related: Profile})
profile;
}
export class Profile extends Model {
#HasOneColumn({related: Image})
image;
}
export class Image extends Model {
name;
}
eager load
User.createQuery().with('profile.image').get()
lazy load
const user = await User.createQuery().first();
const image await (await user.profile).image