Before configuring the application, let’s start by preparing a list of tables and columns from our database. We need this information to configure:

  • Object types: Each table will become one object type in our package.
  • Attribute types: Each column with values (e.g., description) will be defined as an attribute type.
  • Attribute mapping: Knowing what attributes we have, allows us to quickly and correctly link our source fields to the Dawiso attributes.
Tip

If you are already familiar with this step, skip ahead to Basics of a Metadata Application. Download the full examples we used in this tutorial to follow along: - Recipe Manager (version data ingestion): Recipe Manager (Metadata Application).json - SQL script with the example database: Recipe SQL Script.sql

Prepare a List of Tables and Columns

First, use a SQL query (with the DISTINCT function if needed) to extract a list of tables and their unique column names from your database. This will give you a list of object types (tables) and attribute types (columns), which you can immediately create in your package configuration.

SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
ORDER BY TABLE_NAME ASC;

SELECT DISTINCT
    COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
  AND LOWER(COLUMN_NAME) NOT LIKE '%ID'
  AND LOWER(COLUMN_NAME) <> 'Name'
ORDER BY COLUMN_NAME;

Note that we excluded all primary keys (PK), foreign keys (FK), and name columns, as these serve as identifiers and are automatically ingested and processed by the system.

  • Primary keys uniquely identify each row in a table (all have ID in their name).
  • Foreign keys establish relationships between tables by referencing primary keys from other tables.
  • Name fields often serve as human-readable labels for objects and are also treated as identifiers.

The result is a clean list focused on the business-relevant attributes captured across the different object types.

Tip

We use dbo in our table names as it is the default schema for user-defined objects in SQL Server, ensuring consistency and clarity in ownership. It also helps us easily filter only the tables we want, excluding system or integration-specific schemas.

Also see Databases Best Practices!

Recipe Manager: Example Data

Relations Diagram

In the entity-relationship diagram below, you can see the structure of our example Recipes database:

  • Which tables exist,
  • The columns they contain,
  • And how they relate to one another.

Each table represents a distinct object type with the following parent-child relations:

  • | The [Cuisine] object type is a parent to [Recipe].

A [Recipe] can be a parent to a [Recipe Step] or a [Recipe Review]. | A [Cuisine] can be a parent to another [Cuisine]. |

| --- | --- |
| Then we have the [Ingredient Category] which can be parent to [Ingredient] object types. | An [Ingredient Category] can also be a parent to another [Ingredient Category]. |
| Finally, we have the [Dietary Category] object type. | A [Dietary Category] can be a parent to another [Dietary Category]. |
  • This information will later be used to define the object hierarchy.

Then, we also have relations between different object types:

  • [Recipe] “is recommending” a [Recipe]
  • [Recipe step] “requires” an [Ingredient]
  • [Dietary Category] “requires” an [Ingredient]
  • [Recipe] “has dietary category” [Dietary Category]

Table View

To generate a simplified overview of the data model, we used the SQL queries above to extract a list of unique table and column name pairs.

  • Each table in your source system represents either an object type or a relation in your metadata app. The highlighted cells in the table below correspond to object types and will each require a dedicated ingestion query.
  • Each distinct column across these tables represents an attribute type that must be defined in the package. To ensure correct ingestion, each column must be properly mapped to its corresponding attribute type.
Tip

For more information on object types and attribute types creation, refer to Writing an Application Package.

TABLE_NAME
Cuisine
DietaryCategory
DietaryCategoryIngredient
DietaryCategoryRecipe
Ingredient
IngredientCategory
Recipe
RecipeRecommendation
RecipeReview
RecipeStep
RecipeStepIngredient
COLUMN_NAME
Description
Difficulty
InStock
LastMade
Tip

Although the diagram shows relations between object types as simple lines, each relation is actually stored in its own table in the database.

For example, since one recipe can recommend multiple others, the relations must be managed through a dedicated table referencing only recipe IDs.

This is a common approach in databases to support many-to-many relationships. An example of such a table will be: RecipeID: RecommendedRecipeID; 1: 4; 2: 5; 3: 6

Click here to hide the example.For reference, the following SQL script returns the complete list of all tables and their columns from our example database, including the relation tables that define links between objects:

SELECT
    TABLE_NAME,
    COLUMN_NAME,
    DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
ORDER BY TABLE_NAME, ORDINAL_POSITION;
The query produces the following result set:
TABLE_NAMECOLUMN_NAMEDATA_TYPE
CuisineCuisineIDint
CuisineNamenvarchar
CuisineParentIDint
CuisineDescriptionnvarchar
DietaryCategoryDietaryCategoryIDint
DietaryCategoryNamenvarchar
DietaryCategoryDescriptionnvarchar
DietaryCategoryParentIDint
DietaryCategoryIngredientDietaryCategoryIngredientIDint
DietaryCategoryIngredientDietaryCategoryIDint
DietaryCategoryIngredientIngredientIDint
DietaryCategoryIngredientDietaryCategoryRecipeIDint
DietaryCategoryIngredientDietaryCategoryIDint
DietaryCategoryIngredientRecipeIDint
DietaryCategoryRecipeDietaryCategoryRecipeIDint
DietaryCategoryRecipeDietaryCategoryIDint
DietaryCategoryRecipeRecipeIDint
IngredientIngredientIDint
IngredientNamenvarchar
IngredientIngredientCategoryIDint
IngredientDescriptionnvarchar
IngredientInStockbit
IngredientCategoryIngredientCategoryIDint
IngredientCategoryNamenvarchar
IngredientCategoryDescriptionnvarchar
IngredientCategoryParentIDint
RecipeRecipeIDint
RecipeCuisineIDint
RecipeNamenvarchar
RecipeDescriptionnvarchar
RecipeDifficultynvarchar
RecipeLastMadedatetime
RecipeRecommendationRecipeRecommendationIDint
RecipeRecommendationRecipeIDint
RecipeRecommendationRecommendedRecipeIDint
RecipeReviewRecipeReviewIDint
RecipeReviewRecipeIDint
RecipeReviewNamenvarchar
RecipeReviewDescriptionnvarchar
RecipeStepRecipeStepIDint
RecipeStepRecipeIDint
RecipeStepNamenvarchar
RecipeStepDescriptionnvarchar
RecipeStepIngredientRecipeStepIngredientIDint
RecipeStepIngredientRecipeStepIDint
RecipeStepIngredientIngredientIDint

Basics of a Metadata Application

Using the information above, we can configure our base package with the necessary object types and attribute types.

Now, we can move onto configuring the data ingestion function. To add data ingestion to your package, you will need these assets:

"hierarchyDefinitions": [ ],
"dataSourceDefinitions": [ ],
"dataIntegrations": [ ]
AssetPurpose
hierarchyDefinitionsDefines the hierarchy of the object types. For a metadata application, at least two hierarchy definitions will be needed:Native: This hierarchy is based on the structure of the objects in your database, in other words, it reflects reality. This must be done precisely as it allows objects to be ingested properly., Hybrid: The hybrid hierarchy builds on the native one. After objects are ingested, Dawiso can reorganize them in a more business friendly way by, for example, further categorizing the objects into folders.All hierarchy definitions will be selectable in the left-side navigation panel.
dataSourceDefinitionDefines how data is ingested from an external data source into Dawiso. It configures
to be executed against the external data source to get metadata from it., The visual template for the data source (data source creation UI definition).
dataIntegrationsMaps what fields get ingested as what attributes in Dawiso.
Let’s begin with defining the application’s object hierarchy using the list of object types that we prepared.