Metadata
Before Breeze can treat your data as entities, it needs a description of it: which types exist, their properties and data types, which properties make up the key, and how the types relate to each other. That description is metadata, and it lives in a MetadataStore.
Breeze uses metadata to:
- turn query results into entities and cache them by key
- create new entities with
createEntity - wire navigation properties from foreign keys
- validate property values
- translate property names between client and server
- work out which type a resource name returns, for queries against the cache
Where metadata comes from
There are three sources, and you can combine them:
| Source | Use it when |
|---|---|
| The server | You have a Breeze .NET server. This is the default. |
| A JSON file | You want metadata at startup, offline or in tests, without a round trip. |
| Written by hand | The server can't supply metadata: a non-.NET backend, or a third-party API. |
From the server
By default an EntityManager asks its service for metadata before its first query:
import { EntityManager, EntityQuery } from 'breeze-client';
const em = new EntityManager('/breeze/NorthwindIBModel');
// Fetches /breeze/NorthwindIBModel/Metadata first, then runs the query.
const { results } = await em.executeQuery(EntityQuery.from('Customers'));If you need metadata before you query (to create entities first thing, say), fetch it yourself:
await em.fetchMetadata();
const customer = em.createEntity('Customer', { companyName: 'Acme' });A store fetches metadata for a given service only once. fetchMetadata rejects if the store already has it, so check em.metadataStore.hasMetadataFor(serviceName) when you aren't sure. Queries do this check for you.
Several managers can share one store:
const em2 = new EntityManager({
serviceName: '/breeze/NorthwindIBModel',
metadataStore: em.metadataStore,
});From a file, or by hand
To skip the server request, give the manager a DataService with hasServerMetadata: false and fill the store yourself: either with importMetadata, from JSON you saved earlier, or with addEntityType. Both are covered in Writing metadata by hand.
CSDL and EDMX are not supported
Breeze reads Breeze native JSON metadata only — the format the Breeze .NET server sends and MetadataStore.exportMetadata() writes, described in Metadata in depth.
CSDL, the OData / EDMX format, is rejected rather than half-imported. An object with a schema property and no structuralTypes makes importMetadata() throw This looks like CSDL (OData / EDMX) metadata, which breeze-client 3 does not read, prefixed by Unable to either parse or import metadata. So pointing Breeze at an OData $metadata endpoint, or at a WebApi2 + EF6 server that emits CSDL, fails on the first metadata fetch with that message.
If your metadata is CSDL, Migrating from 2.x has the two ways out.
On the server
The Breeze .NET server builds metadata from your EF Core model. EFPersistenceManager reads the DbContext's model, not the database. The controller exposes the result as a Metadata action, which is where the client looks (<serviceName>/Metadata):
[Route("breeze/[controller]/[action]")]
[BreezeQueryFilter]
public class NorthwindIBModelController : Controller {
private readonly NorthwindPersistenceManager persistenceManager;
public NorthwindIBModelController(NorthwindIBContext_CF context) {
persistenceManager = new NorthwindPersistenceManager(context);
}
[HttpGet]
public IActionResult Metadata() {
return Ok(persistenceManager.Metadata());
}
// query and SaveChanges actions ...
}
public class NorthwindPersistenceManager : EFPersistenceManager<NorthwindIBContext_CF> {
public NorthwindPersistenceManager(NorthwindIBContext_CF dbContext) : base(dbContext) { }
}The server writes property names as they are in C# (CompanyName) and does not send a naming convention. The client's naming convention produces the client-side names: the default, NamingConvention.camelCase, turns CompanyName into companyName. See Naming conventions.
Breeze.Persistence.NH does the same for NHibernate. A server with neither, or a third-party service, sends no metadata. Write it by hand or ship it as a JSON file.
Looking at metadata at runtime
Everything in the store is available to your code:
import { DataType } from 'breeze-client';
const orderType = em.metadataStore.getAsEntityType('Order')!;
orderType.name; // 'Order:#Foo' - shortName:#namespace
orderType.keyProperties.map(p => p.name); // ['orderID']
orderType.getProperty('customer'); // a NavigationProperty
orderType.getDataProperty('orderDate').dataType === DataType.DateTime; // truegetAsEntityType and getAsComplexType accept a short name ('Order') or a qualified one ('Order:#Foo'), and throw if the type isn't there. Pass true as the second argument to get null instead.
The classes involved:
| Class | Describes |
|---|---|
MetadataStore | the whole model, plus the data services it came from |
EntityType | a type with a key, which Breeze caches and tracks |
ComplexType | a keyless value type embedded in an entity (see Complex properties) |
DataProperty | a property holding a value, or a complex object |
NavigationProperty | a property returning a related entity or entities |
DataType | the data type of a DataProperty |
AutoGeneratedKeyType | how new keys are assigned |
In this section
- Metadata in depth: the JSON format, property by property
- Writing metadata by hand:
addEntityType, and loading metadata from a JSON file - Custom metadata: attaching your own information to types and properties