# Building a Dataverse demo dataset

Realistic data is what makes a concept demo credible. Wrong-looking names and round numbers kill it faster than a missing feature.

---

## Build order (dependencies matter)

1. **Price list** — needed before price-list items
2. **Products** — 10–15 is plenty; use real SKUs/terminology from the customer's industry and language
3. **Price list items** — one per product
4. **Accounts** — 8–12, tiered (top / mid / small)
5. **Contacts** — 1–3 per key account, with *roles that matter* (buyer, approver, site contact, admin)
6. **Opportunities / projects** — spread across stages and owners
7. **Line items** on the hero opportunity — then **verify the total**
8. **Quote** (only if the customer actually uses quotes — many don't)
9. **Orders** — a couple fulfilled, for purchase history
10. **Activities** — emails, calls, appointments; then close them
11. **Leads** — scored, with a range of quality
12. **Custom KPI fields** if the story needs data the standard schema lacks

---

## Design the data around the story

A dataset where everything is healthy has nothing to demo. Deliberately seed the conditions your screens exist to surface:

| Seed this | So you can show |
|---|---|
| Accounts with no purchase for N weeks | Dormancy / churn risk |
| Accounts buying only one category | Category-gap / cross-sell |
| Deals with no activity for N days | Stalled pipeline |
| Deals all closing on the same date | A data-hygiene problem the customer has |
| Leads with a wide score spread | Prioritisation |
| A named hero account | The end-to-end walkthrough |

Give the hero account a full, coherent history: contacts with distinct roles, a timeline of activities that tells a story, an open deal with real line items, and prior fulfilled orders.

**Mirror the customer's own metrics.** If they measure four category objectives, build four categories. If their attainment on the commodity category is high and the margin categories lag, reproduce that shape — showing customers their own pattern back is far more persuasive than generic sample data.

---

## Dataverse MCP quirks (these will cost you time)

### `create_record` / `update_record` — quoting

The `item` payload must use **single-quoted** keys and values. Double-quoted JSON fails with `JObject does not match String`.

```
item: {'name':'Contoso', 'revenue':125000}
```

Lookups take an object:
```
{'recordId':'<guid>', 'relatedTable':'account'}
```

### `read_query` — a restricted SQL dialect

- Hard cap of **TOP 20** rows
- **No** `CAST`, `CASE`, `DISTINCT`, subqueries, `HAVING`, `UNION`, `OFFSET`, date functions
- Aggregates only: `COUNT SUM AVG MIN MAX`
- `GETDATE()` / `GETUTCDATE()` work in predicates but not in the SELECT list
- Column names are case-sensitive and are **logical** names — always `describe` first, never guess from display names
- Some tables use non-standard audit columns (e.g. `createdtime` rather than `createdon`)

### Rollup lag on bulk insert

Creating line items in parallel leaves the parent's calculated total **stale**. Force a recalculation by updating any one child record afterwards, then re-read the parent and confirm the total.

**Always verify computed totals before demoing.** This one is silent and embarrassing.

### Workflows fire on create

Creating a Quote may trigger an out-of-box workflow that generates a junk record (e.g. a templated email with placeholder text). Check for unexpected child records after creating anything with standard automation attached, and repurpose or delete them.

### `update_table` requires `newDisplayName`

Even when you are only adding columns.

### Solution import lock

Concurrent imports fail with *"another [Import] running."* Wait ~110 s and retry. Imports of a small solution routinely take 2–5 minutes — budget for it.

### Activities create as Open

Close them with a **second** update setting `statecode` / `statuscode`. Typical values:

| Activity | statecode | statuscode |
|---|---|---|
| Phone call (made) | 1 | 2 |
| Email (sent) | 1 | 3 |
| Email (received) | 1 | 4 |
| Appointment | 1 | 3 |

Sales orders can be set fulfilled with `statecode 3 / statuscode 100001`.

### Currency

Demo orgs are frequently single-currency. If the customer operates in another currency, decide up front whether to relabel in the UI layer or configure the currency properly — and note it in the demo handoff so nobody is surprised live.

---

## Verify before you demo

```
- [ ] Parent totals match the sum of their children
- [ ] No junk records created by workflows
- [ ] Activities are closed, not sitting Open
- [ ] Every account has the fields your screens read
- [ ] Owner spread looks like a real team, not one user
- [ ] Dates are relative to demo day, not the day you built it
- [ ] Names/addresses are plausible for the customer's country
```

**Re-date before every demo.** Nothing undermines a "this is today's priority list" screen like a timeline ending three months ago.

---

## Write a demo handoff note

Record what you built, where, and the GUIDs: environment ID, org URL, solution name, hero record IDs. Future-you and whoever inherits the account will need them.

If the dataset is later superseded, put a supersession banner at the top rather than deleting the file.
