This library provides tools for making Revit Extensible Storage API similar to Entity Framework. Define your models, add them to SchemaContext. Run Schema Migration Generator to create migration. Then save your models in ES and load them from ES as instances of your Models class, not only primitive objects.
You can install this tool as a nuget package.
Packages are compiled for a specific version of Revit, to support different versions of libraries in one project, use RevitVersion property.
<PackageReference Include="Atomatiq.SchemaMigrations.Database" Version="$(RevitVersion).*"/>
Create a solution for your Revit Application. You can use Nice3Point Revit Templates, but it is not mandatory.
You should create one project for your solution which will be responsible for working with Extensible Storage (next: Database project). Other projects would have references on it if they needed.
Add reference to nuget-package SchemaMigrations.Database in the Database project. You should use the version of the package according to your Revit Version, or simply change your .csproj like this if you are using Nice3Point or similar template:
<PackageReference Include="Atomatiq.SchemaMigrations.Database" Version="$(RevitVersion).*" />
- Create Models folder and define your Model:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Occupation { get; set; }
public List<string> Hobbies { get; set; } = [];
public Dictionary<string, int> Scores { get; set; } = [];
}
You can have a maximum of 256 properties in your model class. The supported property types are Boolean, Byte, Int16, Int32, Float, Double, ElementId, GUID, String, XYZ, UV and Entity.
- Create an implementation of SchemaContext class and add a SchemaSet for every model class:
public class ApplicationSchemaContext : SchemaContext
{
public SchemaSet<Person> Persons { get; set; } = [];
}
- Install SchemaMigrations.Generator tool globally:
dotnet tool install Atomatiq.SchemaMigrations.Generator --global
-
Open your terminal and make sure that you are in your Database project folder. Run
cd Directory
to go to Directory. Runcd ..
to go to parent directory. -
Run the following command in terminal:
schema-migration-add InitialMigration
This command will build your solution to affect all the changes and after that start adding a migration.
If you do not want to build, add --no-build
flag:
schema-migration-add InitialMigration --no-build
The command will create a Migrations folder (if needed) and a first migration class called InitialMigration_{datetime_stamp}
:
using SchemaMigrations.Abstractions;
using SchemaMigrations.Database.Schemas;
using SchemaMigrations.Abstractions.Models;
namespace SchemaMigrationsExample.EntityCreator.Database.Migrations;
public class InitialMigration_20241010_0301 : Migration
{
public override Dictionary<string, Guid> GuidDictionary { get; } = new Dictionary<string, Guid>()
{
{ "Persons", new Guid("5c047012-e225-4c9f-b02a-dc7f2aebca5d") },
};
public override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddSchemaData(new SchemaBuilderData()
{
Guid = GuidDictionary["Persons"],
Documentation = "Initial schema for Person",
Name = "Persons",
VendorId = "Atomatiq"
},
new SchemaDescriptor("Persons")
{
Fields = new List<FieldDescriptor>()
{
new FieldDescriptor( "Id", typeof(Int32) ),
new FieldDescriptor( "Name", typeof(String) ),
new FieldDescriptor( "Surname", typeof(String) ),
new FieldDescriptor( "Occupation", typeof(String) ),
new FieldDescriptor( "Hobbies", typeof(List<String>) ),
new FieldDescriptor( "Scores", typeof(Dictionary<String, Int32>) )
}
});
}
}
Now you are all set to create your first schema.
For saving and loading data, you always need an element. Considering you have one, right this code to save a Person object to it:
using var transaction = new Transaction(instance.Document, "Seeding database");
transaction.Start();
var connection = new DatabaseConnection<Person>(instance);
var person = new Person
{
Id = 69,
Name = "Mirko",
Surname = "Petrović",
Occupation = "Software development",
Scores = new Dictionary<string, int>
{
{ "Scores", 1 }
},
Hobbies = ["Sports"]
};
connection.SaveObject(person);
transaction.Commit();
That's it! Now your element contains entity of Person schema with six fields. To load an object from this element, use LoadObject():
var connection = new DatabaseConnection<Person>(instance);
var existedPerson = connection.LoadObject(); // connection is generic DatabaseConnection<Person>, so it will return correct type
If you need to add more objects to your schema context, it is not an issue anymore. Add new SchemaSet to your SchemaContext, or modify your models as you need. SchemaMigrations.Generator will create new migrations, and SchemaMigrations.Database package will create a new schema according to new migrations, move all the existing data from old schema to the new one for all the elements, and then delete all the entities of old schema.
Let's add a new Model class, Instrument, and SchemaSet of it to our SchemaContext, and modify the Person class: remove the occupation and add the height.
public class Instrument
{
public string Name { get; set; }
public string Type { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
//public string Occupation { get; set; }
public double Height { get; set; }
public List<string> Hobbies { get; set; } = [];
public Dictionary<string, int> Scores { get; set; } = [];
}
public class ApplicationSchemaContext : SchemaContext
{
public SchemaSet<Person> Persons { get; set; } = [];
public SchemaSet<Instrument> Instruments { get; set; } = [];
}
Then build a project and add new migration.
Go to your Database project folder in the terminal and run the same command:
AddSchemaMigration SecondMigration ${PWD}
It will generate a new migration:
public class SecondMigraion_20241011_1122 : Migration
{
public override Dictionary<string, Guid> GuidDictionary { get; } = new Dictionary<string, Guid>()
{
{ "Persons", new Guid("7fccc4a5-2166-4973-82f4-8c4ed5ce8ef8") },
{ "Instruments", new Guid("5b657730-5315-469c-8b6c-9c8799c51320") },
};
public override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateGuid("Persons", GuidDictionary["Persons"]);
migrationBuilder.AddColumn("Persons", "Height", typeof(Double));
migrationBuilder.DropColumn("Persons", "Occupation");
migrationBuilder.AddSchemaData(new SchemaBuilderData()
{
Guid = GuidDictionary["Instruments"],
Documentation = "Initial schema for Instrument",
Name = "Instruments",
VendorId = "Atomatiq"
},
new SchemaDescriptor("Instruments")
{
Fields = new List<FieldDescriptor>()
{
new FieldDescriptor( "Name", typeof(String) ),
new FieldDescriptor( "Type", typeof(String) )
}
});
}
}
It generated new guid values, Add and Drop Columns commands, and added a new Schema. Great! Now you can create database connection of Person and of Instrument as in the previous chapter
Migration generator now supports adding new schemas, adding columns to schemas and deleting columns from schemas It cannot change the type of property or delete existing schema now