Osy#betaRun it on Osyrin: osyrin.com

Reference / Project

Moving an entity onto a base, with its rows

rebase entity Company onto Party;

When an entity you already have becomes a subtype of a base — your own, or a kit's — its rows become the base's rows with the same ids, so everything that points at them still does. `rebase` in a migration says so; nothing is copied.

stable2 examples compiled by CIprojectdeploymigration

Summary#

You have an entity full of rows, and you want it to derive from a base — a Party of your own, or a kit's Organization. In your source that is one line: entity Company : Party, with the members the base now declares taken out of Company. To a deploy it reads as Company losing those members, and it refuses.

rebase entity Company onto Party; says what really happened: the members moved to the base. The rows stay where they are, with their ids, so every reference to a Company — and every reference a kit makes to its base — finds the same row.

Signature#

migration "companies are parties" {
  from "ast:<hash>";
  to   "ast:<hash>";

  rebase entity Company onto Party;                      // members of the same name
  rebase entity Supplier onto Party { Title -> Name; }   // Supplier.Title is the base's Name
  rebase entity Membership onto Osysharp.Organizations.Membership { User -> Member; }
}

Description#

Nothing moves. The base takes over the entity's table: a base and its subtypes share one table, so the base simply adopts the one that already holds the rows. Each member the entity used to declare keeps its column under the base's name for it — the same name, or the one the map in braces gives. No row is copied and no id changes.

The rows stay what they were. Types that share a table are told apart by a hidden column, which the hierarchy gains here. Every row already in the table is given the rebased entity's name, so a Company is still a Company — and, read through the base, the same row is a Party.

If the entity is no longer declared, its rows become plain rows of the base. That is how an entity of your own is replaced by a kit's: rebase entity Membership onto Osysharp.Organizations.Membership { User -> Member; }.

What the base does not carry is not quietly lost. A member the entity used to declare that the base does not declare (and the entity no longer declares either) refuses the deploy by name:

`rebase entity Company onto Party` does not carry Company.Notes: Party declares no Notes. Map it to the base's
member of another name (`rebase entity Company onto Party { Notes -> <TheBasesName>; }`), keep it on Company, or
retire it with `drop property Company.Notes;`.

You do not have to write it. osy compile --generate-migration writes rebase entity X onto B; for every entity that was a root and now derives from a base, keeps a drop property only for a member the base does not declare, and marks each line INFERRED for you to check.

Several entities onto one base. A base and its subtypes share one table, so a base adopts one: the table of the first entity rebased onto it. Every other entity rebased onto the same base — in the same migration, or onto a base an earlier version already has — has its rows moved into that table in the deploy, with their ids, and every reference to them is re-pointed, so it still finds the same row. The old table is left empty. If the rows cannot all live in one table — two of them share a member the base declares [Unique] — the deploy is refused by name and nothing changes.

The same on every deploy. osy compile --new-version locally and osy deploy to Osyrin Cloud carry a rebase the same way: a single rebase keeps its table, several onto one base move their rows inside the deploy's one transaction, and a cloud deploy's dry run tries the move first, so a move the data cannot take is refused before anything is backed up or changed.

Examples#

A Company that becomes a kind of Party:

entity Company {
  [Required, MaxLength(200)] string Name;
  [MaxLength(40)] string? Slug;
}
entity Contact {
  [Required, MaxLength(200)] string FullName;
  Company? Employer;
}
entity Party {
  [Required, MaxLength(200)] string Name;
}
entity Company : Party {
  [MaxLength(40)] string? Slug;
}
entity Contact {
  [Required, MaxLength(200)] string FullName;
  Company? Employer;
}

The migration that says so:

migration "companies are parties" {
  from "ast:<the deployed hash>";
  to   "ast:<the new hash>";

  rebase entity Company onto Party;
}

Deploy it and every Company you had is still there under its id, with its name — now the base's member — and its slug. Party.Where(…) finds them too, and every Contact.Employer still points at its company.

See also#

Related

Renaming and removing things that hold data

Renaming an entity or property, and removing one, are changes to something that already holds rows. Say what you meant…

Deploying while workflows are running

A workflow run can outlive the deploy that started it. Deploying with --new-version freezes the code and data shape the…

entity

Declares a persisted type — a table of rows the app stores, queries and secures. Every entity gets an Id from the…