Bean & Bark: your model is the schema

View .md

In Part 1 you shaped keys by hand — CUSTOMER#c-014, begins_with(sk, 'ORDER#') — and held the whole design in your head. That works for anyone with a DynamoDB table. This is Part 2: you're not just querying Bean & Bark anymore, you're building it on the Kanject platform — where you write the model once as annotated C#, and the keys, the schema DynoStudio reads, and (next chapter) your data-access code all flow from that one place.

You'll learn
  • Scaffold a Kanject service and its dev / stage / prod stages with the kanject CLI
  • Declare keys and a uniqueness constraint as attributes on a plain C# class
  • See DynoStudio read that same model — schema, markers, and access patterns — with nothing defined twice

One command, one model

kanject new scaffolds the service from a template; kanject init writes its manifest and one stage file per environment — the same dev / stage / prod you learned to respect in Part 1, now created for you:

bash
# scaffold the service from a template, then wire its stageskanject new kbs-lambda-netcore-api --name bean-and-barkkanject init --stages dev,stage,prod --region eu-west-1

Now the model. Instead of remembering that a customer's key is CUSTOMER#{id}, you declare it — and you mark the email unique, right on the property:

csharp
using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Annotations.Attributes;[Table("BeanAndBark")]public class Customer{    [KeyTemplate("CUSTOMER#{CustomerId}")]   // the partition key, declared    public string Pk { get; set; }    [KeyTemplate("PROFILE")]                 // one profile row per customer    public string Sk { get; set; }    public string CustomerId { get; set; }    public string Name { get; set; }    [Unique("Email")]                        // one account per email — enforced    public string Email { get; set; }    public string Region { get; set; }}

Open this in DynoStudio's Model Builder and it parses the very same file. The entity, its key templates, and the marker all appear — because the studio reads exactly the attributes you wrote. There is no second schema to define, and nothing to keep in sync.

csharp
// generated from [Unique("Email")] — the email is the argument, no query to writeCustomer? ada = await customers.FindCustomerByEmailAsync("ada@beanandbark.co");
Recap
  • On Kanject, the model is the source: kanject init scaffolds the service and its dev/stage/prod stages, and keys are attributes ([KeyTemplate]), not strings you remember.
  • DynoStudio reads the same annotated C# your app is built from — so its schema, markers, and access patterns are never defined twice.
  • [Unique("Email")] is one attribute that yields both a generated FindCustomerByEmailAsync and a table-enforced uniqueness constraint (a $$Unique#… reserved row).
Check yourself2
On the Kanject platform, where does DynoStudio get its understanding of your schema?
What does [Unique("Email")] on a property give you?
Try it yourself 1
1 Model the product
Add a Product entity to the same BeanAndBark table: its partition key is PRODUCT#{Sku}, and the SKU must be unique.
Same shape as Customer: a [Table("BeanAndBark")] class, a [KeyTemplate] on the key property, and [Unique(...)] on the SKU.
Show solution
A [Table("BeanAndBark")] class with [KeyTemplate("PRODUCT#{Sku}")] on the key and [Unique("Sku")] on the SKU — which generates FindProductBySkuAsync and guarantees no two products share a SKU.
csharp
[Table("BeanAndBark")]public class Product{    [KeyTemplate("PRODUCT#{Sku}")] public string Pk { get; set; }    [KeyTemplate("PROFILE")]       public string Sk { get; set; }    [Unique("Sku")] public string Sku { get; set; }    public string Name { get; set; }}
Was this page helpful?