I have a user table, and one of the columns is contacts which references itself. Now I am trying to get all the user’s contacts. However it is not returning the references. I am not exactly sure are to where the problem can be. Lets say I have a user table that looks like this
id | name | email | contacts_Id
---|---------|---------------------------|-----
1 | foo | foo#foo.com | 2
2 | bar | bar#bar.com | 1
3 | baz | baz#baz.com | 1 2
The entity is like this:
export class User {
#PrimaryGeneratedColumn()
public id: number;
#Column()
public email: string;
#ManyToOne(type => User, user => user.contacts, {
cascade: true,
})
public contact: User;
#OneToMany(type => User, user => user.contact)
public contacts: User[];
}
and I am querying like this:
const userRepo = getManager().getRepository('users');
const data = (await userRepo.findOne({ where: { email: email }, relations: ['contacts'] })) as UserData;
with the code above I get the user data (id, name, email) the contacts section is empty []
solved:
change:
const data = (await userRepo.findOne({ where: { email: email }, relations: ['contacts'] })) as UserData;
to
const data = (await userRepo.findOne({ where: { email: email }, relations: ['contacts'] })) as User;
since we are referencing the entity
I literally did the same thing (copied your entity), difference being that I injected repository into my service, I'm using mySQL, and I guess you're using PostgreSQL but it works for me.
The thing that is bugging me is your column contacts_Id, by default typeorm will generate a camel case foreign key column (contactId) unless specified differently by JoinColumn() decorator, so maybe that's what causing the issues.
(I wanted to comment but don't have enough rep to post a comment.)
Related
In the project setting, I have 2 entities: Organization and Issue. One such "organization" has many "issues" belonging to it.
Issue has a column named status and the values are "Done", "In Progress", "Rejected", etc.
Given an organizationId, I am trying to find the organization with all its issues, except for those whose status is 'Done'.
Organization:
class Organization extends BaseEntity {
... other code
#OneToMany(
() => Issue,
issue => issue.dstOrg,
)
receivedIssues: Issue[];
}
Issue:
class Issue extends BaseEntity {
... other code
#Column('varchar')
status: IssueStatus;
}
Some helper code:
type EntityConstructor = typeof Organization | typeof User | typeof Issue | ...
const findEntityOrThrow = async <T extends EntityConstructor>(
Constructor: T,
id: number | string,
options?: FindOneOptions,
): Promise<InstanceType<T>> => {
const instance = await Constructor.findOne(id, options);
if (!instance) {
throw new EntityNotFoundError(Constructor.name);
}
return instance;
};
If the query does not limit the status of Issues:
const organizationId = 1;
const organization = await findEntityOrThrow(Organization, organizationId, {
relations: ['receivedIssues'],
});
console.log(organization.receivedIssues)
It works well. organization now contains a receivedIssues field and it contains all the issues.
However, the code that does the complete query fails:
const organizationId = 1;
const organization = await findEntityOrThrow(Organization, organizationId, {
relations: ['receivedIssues'],
where: {
receivedIssues: {
status: Not('Done')
}
}
});
console.log(organization.receivedIssues)
This throws an error:
EntityColumnNotFound: No entity column "receivedIssues" was found.
Why am I missing?
Second Question:
If I do not use the helper function and use findOne() directly:
const organization = await Organization.findOne(organizationId, {
relations: ['receivedIssues'],
where: {
receivedIssues: {
status: Not('Done')
}
}
})
const allReceivedIssues = organization.receivedIssues;
I get this error:
src/controllers/organizations.ts:71:29 - error TS2532: Object is possibly 'undefined'.
71 const allReceivedIssues = organization.receivedIssues;
How can I fix this one if I want to use findOne() directly instead of the helper function?
I have a Call entity that contains a user with a ManyToOne relation (and some other irrelevant fields).
So, the entity looks like that:
#Entity()
export class Call extends BaseEntity {
#ManyToOne(() => User, {cascade: true, eager: true})
user: User;
}
I want to update that Call so it will be connected to userId 1 (for example).
When I am trying to update the call with other userID - I am getting a TypeError:
Call.update({ id: 1 }, { user: 2 })
(Because type number is not from type User)
What is the best way of doing that (without using "any")?
Should be
Call.update(1, { user: { id: 2, ...other props } })
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'],
});
I have created an inner join criteria to show a list of elements in the backend.
This are my models:
user:
name: { type: varchar(255) }
age: { type: integer }
article:
title: { type: varchar(255) }
content: { type: varchar(255) }
user_id: { type: varchar(255) }
and this is my generator.yml (a part) of the article module:
list:
peer_method: getArticles
display: [title, content, age]
And this is the method getArticles():
public static function getArticles()
{
$con = Propel::getConnection();
$sql = "select * from article LEFT JOIN user ON article.user_id = user.id";
$stmt = $con->prepare($sql);
$result = $stmt->execute();
$articles = self::populateObjects($stmt);
return $articles;
}
As you can see I want to show the column corresponding to the "age" field, so when I try to show the list of articles an error that says something like "The method Articles::getAge() is not defined".
So I think I should create the method Articles::getAge(), but.. what should i write inside? A new criteria that retrieves the user object corresponding to the value of the field user_id of the article? Or maybe am i wrong with any other stuff?
sf 1.4/propel
Regards
Javi
Yes:
class Articles
{
public function getAge()
{
return $this->getUser()->getAge();
}
}
or similar code to retrieve the value based on your related model - I use Doctrine normally, but from my hazy Propel memory I think the above should work :-)