# reading data inside an action

> A data read written inside an `action`, `method` or lifecycle hook runs at that point in the body: the platform fetches it from the server and the body continues with the rows. It is not a page-load value and has no `var` / `live var` decision to make, because a body runs once — when the user triggers it.

<!-- id: ui-read-in-a-body · area: ui · stability: stable · html: https://osysharp.com/reference/ui/read-in-a-body/ -->

## Summary        {#summary}

Write the read where you need the answer.

```osy syntax
action Refresh() {
  var rows = Order.Where(o => o.Code == code);
  found = rows.Count();
}
```

The read happens on the server, when the click happens. The body waits for it and carries on — the same way it waits
for a server function it calls.

## Signature      {#signature}

```osy syntax
action <Name>(…) {
  var <rows>  = <Entity>.Where(…).OrderBy(…);          // the rows
  var <one>   = <Entity>.SingleOrDefault(…);           // one row, or null
  var <n>     = <Entity>.Count(…);                     // how many
  var <any>   = <Entity>.Any(…);                       // whether any
  var <total> = <Entity>.Sum(x => x.<Column>);         // a computed value
}
```

The same is true in a `method`, an `on mount`, an `on change` and every other imperative member. A **render**
expression is a different question — see [component](https://osysharp.com/reference/ui/component/).

## Description    {#description}

### Why this is not the same as a page-load query   {#vs-declaration}

A component member is a **binding**: it is re-evaluated as the page renders, so declaring one makes you choose what
should happen when its inputs change — `var` fetches once and can go stale, `live var` re-reads and pays a round trip
each time. That choice is real, and it is why a read cannot simply be hoisted for you.

**A body is not a binding.** It runs once, at the moment the user triggers it. There is no "when should this happen
again?", nothing can go stale, and there is no decision for anyone to take. So the read simply runs, there, then.

That distinction is the whole feature, and it decides where to put a read:

| you want | write it |
|---|---|
| something the page SHOWS | a member — `var` for a snapshot, `live var` to follow changes |
| something an action NEEDS in order to act | the read, in the action |

Putting an action's read on a member is not merely more code. The member is fetched **with the page** — before the
user did the thing that made them want the answer — so the action would act on a picture from earlier.

### What it costs   {#cost}

A round trip, at that point in the body. That is what you asked for by writing it there, and an action is already a
multi-request thing. Two reads in a body are two round trips, in order; if you need them together, ask once.

### Only VALUES cross to the read   {#values-cross}

The read runs on the server. Values you hold travel to it — a local, a component member, a route parameter, the id of
a row you are showing:

```osy title="✓ only values cross — send the id" syntax
action Look(Customer c) {
  var theirs = Order.Where(o => o.Customer.Id == c.Id);   // ✓ a Guid crosses
}
```

A whole **row** does not travel. Comparing against one is refused, and the compiler names the row and shows you the
id form:

```osy title="✗ a whole row cannot cross to the server" syntax
action Look(Customer c) {
  var theirs = Order.Where(o => o.Customer == c);         // ✗ refused: `c` is a row
}
```

This is the same rule everywhere in the language, said once: a row on the client is its identity, and its fields live
in the store. Nothing about it is special to a body.

### What comes back   {#result}

Rows come back as rows: read their fields, loop them, filter them further in memory.

```osy title="what comes back is rows — filter further in memory" syntax
action Look() {
  var rows = Order.Where(o => o.Total > 100);
  var big  = rows.Where(o => o.Priority);     // in memory, no second round trip
  foreach (var o in rows) { Log.Information("{Code}", o.Code); }
}
```

They also land in the page's own store, so a row you then edit is the row the page is already showing — not a
detached copy of it.

### Security is not a question here   {#security}

The read goes out under your own principal and comes back through the same secured read every other query uses. A
body cannot ask for more than the page could, and there is nothing to check or arrange: see [security { }](https://osysharp.com/reference/security/entity-security/).

## Examples       {#examples}

Look something up on a click and show the answer:

```osy title="read on the click" test app=ui-read-in-a-body
entity Note {
  [Required, MaxLength(80)] string Title;
  int Rank;
  security { allow read when IsAnonymous || IsAuthenticated; }
}

[Page("/look")]
[Render(CSR)]
[AllowAnonymous]
component LookPage() {
  int total = -1;

  action Look() {
    var rows = Note.Where(n => n.Rank > 1);
    total = rows.Count();
  }

  render {
    Stack(gap: 2) {
      Text("total:" + total);
      Button("Look", onPress: Look);
    }
  }
}
```

Key the read off something the page holds — the value is read at the click, not at page load:

```osy title="keyed off a component member" test app=ui-read-in-a-body
[Page("/search")]
[Render(CSR)]
[AllowAnonymous]
component SearchPage() {
  string wanted = "";
  string found = "-";

  action Search() {
    var one = Note.SingleOrDefault(n => n.Title == wanted);
    found = one == null ? "none" : one.Title;
  }

  render {
    Stack(gap: 2) {
      Input(value: wanted, placeholder: "Title");
      Text("found:" + found);
      Button("Search", onPress: Search);
    }
  }
}
```

Ask a question rather than fetching rows to count them:

```osy title="Count, Any and Sum" test app=ui-read-in-a-body
[Page("/tally")]
[Render(CSR)]
[AllowAnonymous]
component TallyPage() {
  int total = 0;
  string state = "-";

  action Tally() {
    total = Note.Sum(n => n.Rank);
    state = Note.Any(n => n.Rank > 2) ? "has-high" : "all-low";
  }

  render {
    Stack(gap: 2) {
      Text("total:" + total);
      Text("state:" + state);
      Button("Tally", onPress: Tally);
    }
  }
}
```

## See also       {#see-also}
- [component](https://osysharp.com/reference/ui/component/) — declaring a component, and its `var` / `live var` members: the read a page SHOWS, and the
  choice that comes with it
- [Session.CurrentUser](https://osysharp.com/reference/ui/current-user/) — the one read that is fetched with the page, because it has no inputs that can change
- [creating & saving data](https://osysharp.com/reference/ui/data-mutation/) — writing in an action, and when the write is committed
- [security { }](https://osysharp.com/reference/security/entity-security/) — who may read what, declared once on the entity
