Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot populate @OneToMany when using Embeddables #4090

Open
pantajoe opened this issue Mar 3, 2023 · 2 comments
Open

Cannot populate @OneToMany when using Embeddables #4090

pantajoe opened this issue Mar 3, 2023 · 2 comments
Labels
enhancement New feature or request

Comments

@pantajoe
Copy link

pantajoe commented Mar 3, 2023

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
@B4nan
Copy link
Member

B4nan commented Mar 3, 2023

This is not supported - you could tell by the need to cast things to any to be able to define this. You can't define inverse side of such relation because embedded entity does not have a primary key, hence it has no identity.

I'll keep this open as a feature request, as it could work for inlined mode. It is partially connected to #3887, the root cause is the same.

@B4nan B4nan added the enhancement New feature or request label Mar 3, 2023
@pantajoe
Copy link
Author

pantajoe commented Mar 3, 2023

Thanks for you quick response! Yeah, that's what I figured. Wasn't sure whether to declare this issue as a feature request or a bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants