fsprojects / SQLProvider

A general F# SQL database erasing type provider, supporting LINQ queries, schema exploration, individuals, CRUD operations and much more besides.
https://fsprojects.github.io/SQLProvider
Other
564 stars 144 forks source link

Migration guide to 1.3.x #805

Closed Thorium closed 8 months ago

Thorium commented 8 months ago

The migration is not as bad as initial code red lines may show.

  1. The static parameter of UseOptionTypes: bool changed to FSharp.Data.Sql.Common.NullableColumnType enum where the items are listed below. For easiest migration just select value corresponding your old value.

    • NO_OPTION - old "false"
    • OPTION - old "true"
    • VALUE_OPTION - totally new option using voption type, which has benefits of option but with lighter weight object-capsuling.
  2. Async changed to task. So basically if you don't want to migrate too much and used async before, just use |> Async.AwaitTask after each call. Later you can consider should you change your asyncs to tasks or not (i.e. are they just small operations (task) or workflows (async) with timeouts, cancellations, etc).

jimfoye commented 2 months ago

What was the rationale for number 2?

Thorium commented 2 months ago

Async and task are designed from a bit separate point of view: Async is good when you have many complex parallel workflows. Task is good when you want to execute a small thing now. Task is performance-wise way more faster. Most of SQLProvider things are "please execute me this query now", so the new task computation fits to SQLProvider scenario better.

All the database drivers that SQLProvider is using, are using tasks. Most of the APIs that SQLProvider is used in, are also now task-based. So there was no point of converting task->async->task.

That been said I cannot blindly recommend converting everything to task. I'd say as a rule of thumb: if you have a function that is less than 30 F# lines, then convert it to task. But if you have functions over e.g. 150 lines capsulated to task, they probably will just break runtime unless you break them to multiple separate non-nested-functions, to keep your tasks small. So keep them as async and just do Async.AwaitTask. Best indication is that if you compile in release mode and it gives you this warning warning FS3511: This state machine is not statically compilable. A resumable code invocation at '(...-...)' could not be reduced. that means the task might not be working runtime as it should.

jimfoye commented 2 months ago

I prefer async for the usual reasons (especially just that it's easier to reason about), but I see why you did it, thanks for the great explanation.