question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Polymorphic relations

See original GitHub issue

What’s the best way to handle polymorphic relations with MikroORM?

Method 1 This almost seems to work but I don’t know how to make the entity parameter for the OneToOne decorator be dynamic.

@Entity()
export class Plan implements UuidEntity<Plan> {
  @PrimaryKey()
  uuid = v4()

  @OneToOne(() => GaragePlan) // How can I make this return type dynamic?
  node!: IdentifiedReference<DeckPlan | GaragePlan>

  @Property()
  type!: string

  @BeforeCreate()
  async do() {
    const node = await this.node.load()
    this.type = node.type
  }

  constructor(node: GaragePlan | DeckPlan) {
    this.node = Reference.create(node)
  }
}

@Entity()
export class DeckPlan implements UuidEntity<DeckPlan> {
  @PrimaryKey()
  uuid = v4()
 
  // Other properties...

  @Property({ persist: false })
  type = 'DECK_PLAN'
}

@Entity()
export class GaragePlan implements UuidEntity<GaragePlan> {
  @PrimaryKey()
  uuid = v4()

  // Other properties...

  @Property({ persist: false })
  type = 'GARAGE_PLAN'
}

Method 2

I’d rather not use this method.

@Entity()
export class Plan implements UuidEntity<Plan> {
  @PrimaryKey()
  uuid = v4()

  @OneToOne(() => GaragePlan)
  garagePlan?: IdentifiedReference<GaragePlan>

  @OneToOne(() => DeckPlan)
  deckPlan?: IdentifiedReference<DeckPlan>

  @Property()
  type!: string
}

// Same DeckPlan & GaragePlan as in Method 1

Method 3…?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
B4nancommented, Mar 31, 2021

You can’t, no plans to pass entity instance to the custom types, they are handled on places where no entity instance is even present. Their use case is just to convert a value from runtime to db representation, it should not be dependent on other fields.

What you can do is to use STI or maybe onInit hook, depends on what you actually want. This is an old issue, nowadays there is also quite advanced support for embeddables, they might also fit here.

1reaction
B4nancommented, Feb 15, 2020

This is not currently supported. I can imagine this done via single table inheritance (#33), where you would have all of Plan, GaragePlan and DeckPlan entities stored in one table - Plan being the common ancestor with the type as discriminator column. GaragePlan and DeckPlan would extend the (abstract) Plan entity.

Otherwise this can’t work, how would the ORM know what entity to load (which table to look into) based just on the PK? Also I think indexes and referential integrity check could not work this way.

What you could do now on the other hand is to use JSON column for GaragePlan/DeckPlan objects, and implement custom type that would handle picking the right child class for you. This would mean you would have only one table, also you could not have any relations inside your “child entities” (they would not be entities). If you want to rather have it split across 3 tables, method 2 is the way to go.

Something like this could work:

export class NodeType extends Type {

  convertToJSValue(value: any): any {
    if (value.type === 'GARAGE_PLAN') {
      return new GaragePlan(value);
    }

    if (value.type === 'DECK_PLAN') {
      return new DeckPlan(value);
    }

    throw ValidationError.invalidType(NodeType, value, 'database');
  }

  getColumnType() {
    return 'json';
  }

}

export class DeckPlan {
  // Other properties...
  type = 'DECK_PLAN'
}

export class GaragePlan {
  // Other properties...
  type = 'GARAGE_PLAN'
}

@Entity()
export class Plan implements UuidEntity<Plan> {
  @PrimaryKey()
  uuid = v4();

  @Property({ type: NodeType })
  node!: DeckPlan | GaragePlan;

  constructor(node: GaragePlan | DeckPlan) {
    this.node = node;
  }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding Polymorphic Relationships - DevDojo
Before explaining polymorphism, let's do a quick review of the three common relationships: One-to-One; One-to-Many; Many-to-Many. One-to-One.
Read more >
Re-Introducing Eloquent's Polymorphic Relationships - SitePoint
A polymorphic relationship is where a model can belong to more than one other model on a single association. To clarify this, let's...
Read more >
Eloquent: Relationships - The PHP Framework For Web Artisans
Many To Many (Polymorphic). Defining Relationships. Eloquent relationships are defined as methods on your Eloquent model classes. Since relationships also serve ...
Read more >
Polymorphic relationships in Laravel and their use cases
The general concept behind using polymorphic relationships revolves around identifying similarities between what two or more models might need ...
Read more >
Polymorphic relations | LoopBack Documentation
LoopBack supports polymorphic relations in which a model can belong to more than one other model, on a single association. For example, you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found