Skip to content

Inserting a nested ManyToOne relation with composite PK throws an error if the nested entity has a DB-default value #3965

@RDSM-CM

Description

@RDSM-CM

Describe the bug
MikroORM throws an error when trying to insert an entity with a composite primary key that includes a @ManyToOne foreign key which is also a composite primary key. The issue seems to occur when MikroORM tries to reload the inserted entity to hydrate its database-set default values.

Steps to reproduce

  1. Define entities:
@Entity()
export class Category {
  @PrimaryKey({
    length: 36,
  })
  public id: string

  @Property({
    defaultRaw: "CURRENT_TIMESTAMP",
  })
  public createdAt?: Date

  @OneToMany(() => Article, (attr) => attr.category, {
    cascade: [Cascade.ALL],
  })
  public articles = new Collection<Article>(this)
}

@Entity()
export class Article {
  @PrimaryKey({
    length: 36,
  })
  public id: string

  @Property({
    defaultRaw: "CURRENT_TIMESTAMP",
  })
  public createdAt?: Date

  @ManyToOne(() => Category, {
    primary: true,
    ref: true,
  })
  public category: Ref<Category>

  public [PrimaryKeyType]?: [string, string]

  @OneToMany(() => ArticleAttribute, (attr) => attr.article, {
    cascade: [Cascade.ALL],
  })
  public attributes = new Collection<ArticleAttribute>(this)
}

@Entity()
export class ArticleAttribute {
  @PrimaryKey({ length: 36 })
  public id: string

  @Property({
    defaultRaw: "CURRENT_TIMESTAMP",
  })
  public createdAt?: Date

  @ManyToOne(() => Article, {
    primary: true,
    ref: true,
  })
  public article: Ref<Article>

  public [PrimaryKeyType]?: [string, [string, string]]
}
  1. Create entities:
const category = new Category()
category.id = randomUUID()

const article = new Article()
article.id = randomUUID()

category.articles.add(article)

const articleAttribute = new ArticleAttribute()
articleAttribute.id = randomUUID()

article.attributes.add(articleAttribute)
  1. Try to insert them:
await em.persistAndFlush(category)

Expected behavior
The entities are inserted into the database.

Actual behavior
em.persistAndFlush() throws an error:

Error: Trying to query by not existing property ArticleAttribute.category
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNode.js:28:27
      at Array.forEach (<anonymous>)
      at new CriteriaNode (node_modules/@mikro-orm/knex/query/CriteriaNode.js:23:17)
      at new ScalarCriteriaNode (node_modules/@mikro-orm/knex/query/ScalarCriteriaNode.js:9:1)
      at Function.createScalarNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:25:22)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:22:21)
      at Function.createObjectItemNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:54:25)
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:45:28
      at Array.reduce (<anonymous>)
      at Function.createObjectNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:44:45)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:20:25)
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:32:28
      at Array.map (<anonymous>)
      at Function.createArrayNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:31:32)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:17:25)
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:32:28
      at Array.map (<anonymous>)
      at Function.createArrayNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:31:32)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:17:25)
      at Function.createObjectItemNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:54:25)
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:45:28
      at Array.reduce (<anonymous>)
      at Function.createObjectNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:44:45)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:20:25)
      at Function.createObjectItemNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:54:25)
      at /app/node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:45:28
      at Array.reduce (<anonymous>)
      at Function.createObjectNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:44:45)
      at Function.createNode (node_modules/@mikro-orm/knex/query/CriteriaNodeFactory.js:20:25)
      at QueryBuilder.where (node_modules/@mikro-orm/knex/query/QueryBuilder.js:185:72)
      at MySqlDriver.find (node_modules/@mikro-orm/knex/AbstractSqlDriver.js:37:14)
      at ChangeSetPersister.reloadVersionValues (node_modules/@mikro-orm/core/unit-of-work/ChangeSetPersister.js:270:40)
      at ChangeSetPersister.persistNewEntity (node_modules/@mikro-orm/core/unit-of-work/ChangeSetPersister.js:94:24)
      at processTicksAndRejections (internal/process/task_queues.js:95:5)
      at async ChangeSetPersister.executeInserts (node_modules/@mikro-orm/core/unit-of-work/ChangeSetPersister.js:29:13)
      at async ChangeSetPersister.runForEachSchema (node_modules/@mikro-orm/core/unit-of-work/ChangeSetPersister.js:68:13)
      at async UnitOfWork.commitCreateChangeSets (node_modules/@mikro-orm/core/unit-of-work/UnitOfWork.js:715:9)
      at async UnitOfWork.persistToDatabase (node_modules/@mikro-orm/core/unit-of-work/UnitOfWork.js:667:13)
      at async MySqlConnection.transactional (node_modules/@mikro-orm/knex/AbstractSqlConnection.js:36:25)
      at async UnitOfWork.doCommit (node_modules/@mikro-orm/core/unit-of-work/UnitOfWork.js:287:17)
      at async UnitOfWork.commit (node_modules/@mikro-orm/core/unit-of-work/UnitOfWork.js:260:13)
      at async SqlEntityManager.flush (node_modules/@mikro-orm/core/EntityManager.js:955:9)
      at async SqlEntityManager.persistAndFlush (node_modules/@mikro-orm/core/EntityManager.js:900:9)
      at async Context.<anonymous> (src/__unitTests__/tempTestFile.spec.ts:160:5)

Additional information
Removing primary: true from the relation decorator of ArticleAttribute.article results in successful insertion.

Removing the database-default defaultRaw: "CURRENT_TIMESTAMP" from the ArticleAttribute.createdAt property (and initializing the property when creating the entity) results in successful insertion even when ArticleAttribute.article has primary: true.

Versions

Dependency Version
node 14.17.3
typescript 4.9.4
@mikro-orm/core 5.6.7
@mikro-orm/mysql 5.6.7

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions