Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
741 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
--- | ||
title: Separating Concerns using Embeddables | ||
sidebar_label: Embeddables | ||
--- | ||
|
||
> Support for embeddables was added in version 4.0 | ||
Embeddables are classes which are not entities themselves, but are embedded in | ||
entities and can also be queried. You'll mostly want to use them to reduce | ||
duplication or separating concerns. Value objects such as date range or address | ||
are the primary use case for this feature. | ||
|
||
> Embeddables needs to be discovered just like regular entities, don't forget to | ||
> add them to the list of entities when initializing the ORM. | ||
Embeddables can only contain properties with basic `@Property()` mapping. | ||
|
||
For the purposes of this tutorial, we will assume that you have a `User` class in | ||
your application and you would like to store an address in the `User` class. We will | ||
model the `Address` class as an embeddable instead of simply adding the respective | ||
columns to the `User` class. | ||
|
||
```typescript | ||
@Entity() | ||
export class User { | ||
|
||
@Embedded() | ||
address!: Address; | ||
|
||
} | ||
|
||
@Embeddable() | ||
export class Address { | ||
|
||
@Property() | ||
street!: string; | ||
|
||
@Property() | ||
postalCode!: string; | ||
|
||
@Property() | ||
city!: string; | ||
|
||
@Property() | ||
country!: string; | ||
|
||
} | ||
``` | ||
|
||
> When using ReflectMetadataProvider, you might need to provide the class in decorator options: | ||
> `@Embedded(() => Address)` or `@Embedded({ entity: () => Address })`. | ||
In terms of your database schema, MikroORM will automatically inline all columns from | ||
the `Address` class into the table of the `User` class, just as if you had declared | ||
them directly there. | ||
|
||
## Initializing embeddables | ||
|
||
In case all fields in the embeddable are nullable, you might want to initialize the | ||
embeddable, to avoid getting a null value instead of the embedded object. | ||
|
||
```typescript | ||
@Embedded() | ||
address = new Address(); | ||
``` | ||
|
||
## Column Prefixing | ||
|
||
By default, MikroORM names your columns by prefixing them, using the value object name. | ||
|
||
Following the example above, your columns would be named as `address_street`, | ||
`address_postal_code`... | ||
|
||
You can change this behaviour to meet your needs by changing the `prefix` attribute | ||
in the `@Embedded()` notation. | ||
|
||
The following example shows you how to set your prefix to `myPrefix_`: | ||
|
||
```typescript | ||
@Entity() | ||
export class User { | ||
|
||
@Embedded({ prefix: 'myPrefix_' }) | ||
address!: Address; | ||
|
||
} | ||
``` | ||
|
||
To have MikroORM drop the prefix and use the value object's property name directly, | ||
set `prefix: false`: | ||
|
||
```typescript | ||
@Entity() | ||
export class User { | ||
|
||
@Embedded({ entity: () => Address, prefix: false }) | ||
address!: Address; | ||
|
||
} | ||
``` | ||
|
||
> This part of documentation is highly inspired by [doctrine tutorial](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/embeddables.html) | ||
> as the behaviour here is pretty much the same. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { AnyEntity } from '../typings'; | ||
import { MetadataStorage } from '../metadata'; | ||
|
||
export function Embeddable(): Function { | ||
return function <T extends { new(...args: any[]): AnyEntity<T> }>(target: T) { | ||
const meta = MetadataStorage.getMetadataFromDecorator(target); | ||
meta.class = target; | ||
meta.name = target.name; | ||
meta.embeddable = true; | ||
|
||
return target; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AnyEntity, EntityProperty } from '../typings'; | ||
import { MetadataStorage } from '../metadata'; | ||
import { ReferenceType } from '../entity/enums'; | ||
import { Utils } from '../utils'; | ||
|
||
export function Embedded(options: EmbeddedOptions | (() => AnyEntity) = {}): Function { | ||
return function (target: AnyEntity, propertyName: string) { | ||
const meta = MetadataStorage.getMetadataFromDecorator(target.constructor); | ||
options = options instanceof Function ? { entity: options } : options; | ||
Utils.defaultValue(options, 'prefix', true); | ||
const property = { name: propertyName, reference: ReferenceType.EMBEDDED } as EntityProperty; | ||
meta.properties[propertyName] = Object.assign(property, options); | ||
}; | ||
} | ||
|
||
export type EmbeddedOptions = { | ||
entity?: string | (() => AnyEntity); | ||
type?: string; | ||
prefix?: string | boolean; | ||
nullable?: boolean; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.