Comments (9)
I'm so happy to hear that it worked out for you. It's been nice working together!
Your wish is my command:
Donald/src/Donald.Tests/Tests.fs
Line 412 in d457627
If you enjoy the lib, I'd love a star. And tell all your friends as they say :)
from donald.
uh, and Combine
method is required
A test that doesn't compile currently:
[<Fact>]
member __.``dbResult {...} for...do loop with return`` () =
let cmds =
[1..10]
|> Seq.map (fun n -> dbCommand conn {
cmdText (sprintf "SELECT %i" n)
})
dbResult {
for cmd in cmds do
cmd |> Db.scalar Convert.ToInt32 |> ignore
return
cmd |> Seq.head |> Db.scalar Convert.ToInt32
}
|> shouldNotBeError ignore
If you enjoy the lib, I'd love a star.
I was a sixth one if github keeps the order in the stargazers list
from donald.
Hello again!
Transactional work is already supported through the command expression. See this example:
// Safely begin transaction or throw CouldNotBeginTransactionError on failure
use tran = conn.TryBeginTransaction()
// Build and execute the IDbCommand
dbCommand conn {
cmdText "INSERT INTO author (full_name)"
cmdParam [ "full_name", SqlType.String "John Doe" ]
cmdTran tran
}
|> Db.exec // DbResult<unit>
// Attempt to commit, rollback on failure and throw CouldNotCommitTransactionError
tran.TryCommit()
// OR, safely rollback
tran.TryRollback()
from donald.
Transactional work is already supported through the command expression. See this example:
I'm aware but sample doesn't cover case with uh, let's say 2, 3 and more queries
For now my code looks like (parameters are omitted, names are different)
let addSomething obj1 obj2 =
use conn = openConn()
use tran = conn.TryBeginTransaction()
let res =
dbCommand conn {
cmdText SQLQueries.someQuery1
cmdParam [ ... ]
cmdTran tran
}
|> Db.execSingle
match res with
| Result.Ok number ->
let r2 =
dbCommand conn {
cmdText SQLQueries.someQuery2
cmdParam [ ... ]
cmdTran tran
}
|> Db.execSingle
match r2 with
| Result.Ok id ->
let r3 =
dbCommand conn {
cmdText SQLQueries.someQuery3
cmdParam [ ... ]
cmdTran tran
}
|> Db.execSingle
|> function | Result.Ok _ -> true | _ -> false
if r3 then
if tran.TryCommit () then
{ obj1 with Id = id ; Number = number } |> Some
else
None
else
tran.TryRollback () |> ignore
None
| Result.Error error ->
tran.TryRollback () |> ignore
None
| Result.Error error ->
tran.TryRollback () |> ignore
None
maybe I use it in a wrong way?
from donald.
Ahh the dreaded pyramid of doom! I understand now. You have multiple dependent commands executing within a transaction.
Without seeing your SQL I cannot tell whether this applies or not. But I personally will attempt to write most (if not all) work like this as a single SQL statement that will either all succeed (or fail) as a unit (in SQL Server XACT_ABORT
ensure this for example). Since, as your code insinuates, this is often how these scenarios work anyway. It's much simpler to test and maintain in my experience.
That said, I fully acknowledge this is not always possible and I believe this example perfectly demonstrates the need for
DbResult.bind
, DbResult.map
functions and an associated computation expression dbResult { ... }
.
With that in place your code could become (keep in mind I wrote this in notepad):
let addSomething obj1 obj2 =
use conn = openConn()
use tran = conn.TryBeginTransaction()
let cmd1 = dbCommand conn {
cmdText SQLQueries.someQuery1
cmdParam [ ... ]
cmdTran tran
}
let cmd2 = dbCommand conn {
cmdText SQLQueries.someQuery2
cmdParam [ ... ]
cmdTran tran
}
let cmd3 = dbCommand conn {
cmdText SQLQueries.someQuery3
cmdParam [ ... ]
cmdTran tran
}
dbResult {
let! res = cmd1 |> Db.execSingle
let! r2 = cmd2 |> Db.execSingle
let! r3 =
cmd3
|> Db.execSingle
|> function | Result.Ok _ -> true | _ -> false
if r3 then
tran.TryCommit () |> ignore // this will rollback for you on failure
Some { obj1 with Id = id ; Number = number }
else
tran.TryRollback () |> ignore
None
}
As an aside, I'd inject the
conn
andtran
as function parameters to make the dependencies clearer and more testable. But not core to the problem here.
from donald.
Just added this in. You can test this out in the 6.1.0-beta1 package if you'd like! Would love your feedback!
from donald.
Since, as your code insinuates, this is often how these scenarios work anyway. It's much simpler to test and maintain in my experience.
100%. I just don't know how to do it properly with SQLite. I'll add this to a task list of this project though. But since it is mainly for my use only I doubt I get to it soon.
Just added this in. You can test this out in the 6.1.0-beta1 package if you'd like! Would love your feedback!
Wow! If I knew that it would be so fast I didn't spend so much time to write such awful code like the one above :-)
Just one thing: currently For
method isn't supported, i.e.
let commands =
xs
|> Seq.map(fun item ->
dbCommand conn {
cmdText SQLQueries.someQuery
cmdParam [ ... ]
cmdTran tran
}
)
for command in commands do
command
|> Db.exec
Otherwise works smoothly. At least at first glance.
from donald.
Doh! I'll get that added in.
(And thank you for you very early support)
from donald.
Works like a charm
from donald.
Related Issues (20)
- GetDateTimeOffset Signature is string -> DateTime HOT 1
- Unable to execute query without a transaction HOT 6
- Add a wrapper around ExecuteScalar HOT 6
- CommandBehavior.SequentialAccess causes error with SqlHydra readers HOT 5
- Cast exception when reading DateTimeOffset with System.Data.SqlClient HOT 4
- [Help] How to parse results with sequential access? HOT 2
- Db.Async.execMany throws "A command is already in progress" with NPGSQL HOT 5
- v.7.0.0 HOT 9
- FsDto lib review HOT 2
- Who is @dysme on the landing page? HOT 3
- CancellationToken support
- Support of transaction in newCommand in Fluent syntax HOT 3
- Getting error while using Db.Async.query method HOT 6
- Require help on query HOT 7
- Support or Transition to Microsoft.Data.SqlClient HOT 3
- SQLite: What SQL Type should I choose for a JSON column? HOT 2
- Possible issue with Db.Async.exec throwing instead of returning a Result HOT 1
- How to deal with DB enums in Donald? HOT 1
- DateOnly and TimeOnly parameters
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from donald.