Cannot populate @OneToMany when using Embeddables
Author: pantajoeCreated Mar 3, 2023Updated Mar 3, 2023
Labelsenhancement
Describe the bug
Hey there! First of all, thanks a lot for this very stable and intuitive TS ORM! ❤️
Since a couple of versions, an @Embeddable can have a @ManyToOne relationship through its parent. This works fine.
However, the inverse side that would use a @OneToMany collection cannot populate the user.
Stack trace
No stack trace since no error.To Reproduce
Here is an example setup:
@Embeddable()
export class Address {
constructor(street: string, city: string, country: Country) {
this.street = street
this.city = city
this.country = country
}
@Property()
street!: string
@Property()
city!: string
@ManyToOne()
country!: Country
}
@Entity()
export class Country {
@PrimaryKey({ autoincrement: true })
id!: number
@Property()
name!: string
@OneToMany(() => User, (user) => (user as any).address_country)
users = new Collection<User>(this)
}
@Entity()
export class User {
@PrimaryKey({ autoincrement: true })
id!: number
@Property()
name!: string
@Embedded(() => Address)
address!: Address
}You can populate the country property from the side of the User, but you cannot populate the users collection from the Country's side.
Expected behavior
One should be able to populate the users collection also from the Country's side.
Additional context Here is a test suite that explains everything in detail:
import { MikroORM } from '@mikro-orm/core'
import { SqliteDriver } from '@mikro-orm/sqlite'
import { Address } from './address'
import { Country } from './country'
import { User } from './user'
describe('Issue', () => {
let orm: MikroORM
beforeAll(async () => {
orm = await MikroORM.init({
entities: [User, Country, Address],
dbName: ':memory:',
driver: SqliteDriver,
allowGlobalContext: true,
})
await orm.schema.createSchema()
})
afterEach(async () => {
await orm.schema.clearDatabase()
})
afterAll(() => orm.close(true))
beforeEach(async () => {
const germany = orm.em.create(Country, { name: 'Germany' })
orm.em.create(User, { name: 'John Doe', address: new Address('Main Street', 'Berlin', germany) })
await orm.em.flush()
})
test('the country can be populated through the address of a user', async () => {
const user = await orm.em.findOneOrFail(User, { name: 'John Doe' }, { populate: ['address.country'] })
expect(user.address.country.name).toBe('Germany')
})
test('the users can be populated through the address of a country', async () => {
const country = await orm.em.findOneOrFail(Country, { name: 'Germany' }, { populate: ['users'] })
expect(country.users[0].name).toBe('John Doe') // ❌ this one fails
})
test('can init the user collection of a country', async () => {
const country = await orm.em.findOneOrFail(Country, { name: 'Germany' })
await country.users.init()
expect(country.users.isInitialized()).toBe(true)
expect(country.users[0].name).toBe('John Doe')
})
})Versions
| Dependency | Version |
|---|---|
| node | 16.15.1 |
| typescript | 4.9.5 |
| mikro-orm | 5.6.13 |
| sqlite3 | 5.1.4 |
Source: mikro-orm/mikro-orm