Bean & Bark: the model becomes the code

View .md

You've modelled the store, questioned it, operated it safely, and declared it once as annotated C#. The last step is to ship — and here's the payoff Part 2 was building toward: the model from the last chapter becomes the code your app runs. You'll add referrals to Bean & Bark, and you'll never write the data layer, the schema, or the constraint twice.

You'll learn
  • Generate a data-access method from your model — the raw AWS SDK form, or the terse Kanject repository form
  • Ship a real feature with a new marker (a unique code) and an atomic transaction (dual credit)
  • Close the loop — watch the studio read exactly what the app just wrote

The model was the code all along

That one annotated model has been the source of truth the whole time — the schema DynoStudio reads, the rulebook the table enforces. Now it's the source of your code too. Add [Unique("ReferralCode")] to Customer, hit codegen on the lookup, and the studio emits ready C# — two ways. Take the raw AWS SDK form when you want zero dependencies and can carry the marker's two-step yourself:

csharp
// find a customer by referral code — the marker's two-step, by handvar marker = await ddb.GetItemAsync(new GetItemRequest {    TableName = "BeanAndBark",    Key = {        ["pk"] = new AttributeValue($"$$Unique#ReferralCode#{code}"),        ["sk"] = new AttributeValue("ReservedData"),    },});if (!marker.Item.TryGetValue("RefHashKey", out var refPk)) return null;// the marker row already holds the target's full key — you never guess its skvar found = await ddb.GetItemAsync(new GetItemRequest {    TableName = "BeanAndBark",    Key = { ["pk"] = refPk, ["sk"] = marker.Item["RefRangeKey"] },});

…or take the Kanject repository form, where the marker you declared does exactly that work for you:

csharp
// [Unique("ReferralCode")] generated this — the code IS the argument, the two reads hiddenCustomer? referrer = await customers.FindCustomerByReferralCodeAsync(code);

Sixteen lines become one call — and it isn't a leaky wrapper hiding something you should worry about. It is the [Unique] marker from the last chapter, generating its own reserved-row lookup: the code you pass is exactly the value the marker keys on. Same model, less to get wrong.

Ship it — atomically

Redeeming a referral touches two customers: credit the referrer, credit the new one. Either both happen or neither does — anything else means someone got $5 the other didn't. That's a transaction. Your endpoint calls the generated repository; DynoStudio previews it executing as a native TransactWriteItems, all-or-nothing:

sql
-- redeem: credit both accounts, all-or-nothingBEGIN TRANSACTION;  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500    WHERE pk = 'CUSTOMER#c-014' AND sk = 'PROFILE';   -- the referrer  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500    WHERE pk = 'CUSTOMER#c-207' AND sk = 'PROFILE';   -- the new customerCOMMIT;
Recap
  • Codegen turns an access pattern into ready C# — the raw AWS SDK form, or the terse Kanject repository form that uses the markers you declared.
  • A feature ships with a marker (a unique referral code) and a transaction (both accounts credited, or neither).
  • The studio reads what the app writes: model once, and the schema, the constraints, and the code all agree — no drift, no second definition.
The last check2
The two generated forms — raw AWS SDK vs the Kanject repository — how do they relate?
Redeeming credits two customers. How do you guarantee both are credited, or neither?
Try it yourself 2
1 Add the referral code
Add a unique referral code to the Customer model from the last chapter, so it both generates a lookup and can never collide.
It's the same [Unique(...)] marker you used for Email — one attribute, one property.
Show solution
[Unique("ReferralCode")] on a ReferralCode property generates FindCustomerByReferralCodeAsync and guarantees no two customers share a code — a reserved $$Unique#ReferralCode#… row makes a duplicate impossible.
csharp
[Unique("ReferralCode")]public string ReferralCode { get; set; }
2 Make the credit atomic
Write the transaction that credits two customers 500 cents each — both, or neither.
Wrap two UPDATE ... SET CreditCents = CreditCents + 500 statements (each keyed to a full primary key) in BEGIN TRANSACTION; … COMMIT;.
Show solution
Two keyed UPDATEs inside BEGIN TRANSACTION; … COMMIT; execute as one TransactWriteItems — all-or-nothing, so a referrer is never credited without the new customer.
sql
BEGIN TRANSACTION;  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500    WHERE pk = 'CUSTOMER#c-014' AND sk = 'PROFILE';  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500    WHERE pk = 'CUSTOMER#c-207' AND sk = 'PROFILE';COMMIT;
Was this page helpful?