如何让 SQLProvider 使用 Npgsql 在 Mono 上工作?

问题描述 投票:0回答:1

我在这里创建了一个最小的复制品:https://github.com/mushishi78/transaction-minimal-reproduction

基本上我已经达到了 mono 的

NotImplementedException
 给出的 
TransactionInterop
,这似乎意味着它还没有准备好进行异步事务。但由于我对 .NET 没有那么丰富的经验,我希望得到一些第二意见或建议。

我在实现中做了一些奇怪的事情吗?如果我写得正确,那就完全没问题了?

即使我最初遇到了麻烦,我是否应该努力升级到更高版本的 Npgsql?

我是否应该暂时放弃异步,因为异步在 .NET 世界中可能没有多大区别?

我是否应该放弃 SQLProvider,因为其他 ORM/对象映射器库没有这些问题(例如 Dapper)?

如果不使用 Postgres,我会不会运气更好,因为 SQL Server 在 .NET 世界中得到了更好的支持?

或者单声道还没有准备好迎接黄金时段,我最好让服务器在 Windows 机器上运行?

代码

open FSharp.Data.Sql
open System.Transactions

let [<Literal>] connectionString = "Host=localhost;Database=example;Username=postgres;Password=postgres;Enlist=true"
let [<Literal>] resolutionPath = __SOURCE_DIRECTORY__ + @"..\packages\Npgsql.3.1.0\lib\net451"

type sql = SqlDataProvider<Common.DatabaseProviderTypes.POSTGRESQL,
                           connectionString,
                           ResolutionPath = resolutionPath,
                           UseOptionTypes = true>

let withTransaction fn =
    async {
        use transaction = new TransactionScope (TransactionScopeAsyncFlowOption.Enabled)
        let ctx = sql.GetDataContext ()
        let! result = fn ctx
        transaction.Complete ()
        return result
    }

let createPerson (ctx: sql.dataContext) =
    let row = ctx.Public.Person.Create ()
    row.Id <- 1
    row.Name <- "Hello"
    ctx.SubmitUpdatesAsync ()

let editPerson (ctx: sql.dataContext) =
    query {
       for row in ctx.Public.Person do
       take 1
    }
    |> Seq.iter (fun row -> row.Name <- "Hi there!")
    |> ctx.SubmitUpdatesAsync

let deletePerson (ctx: sql.dataContext) =
    query {
       for row in ctx.Public.Person do
       take 1
    }
    |> Seq.iter (fun row -> row.Delete ())
    |> ctx.SubmitUpdatesAsync

let run (ctx: sql.dataContext) =
    async {
        do! createPerson ctx
        do! editPerson ctx
        do! deletePerson ctx
    }

[<EntryPoint>]
let main argv =
    withTransaction run
    |> Async.RunSynchronously
    |> ignore

    0

堆栈跟踪

  The method or operation is not implemented.
  at System.Transactions.TransactionInterop.GetTransmitterPropagationToken (System.Transactions.Transaction transaction) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-06/external/bockbuild/builds/mono-x64/mcs/class/System.Transactions/System.Transactions/TransactionInterop.cs:57
  at Npgsql.NpgsqlPromotableSinglePhaseNotification.Enlist (System.Transactions.Transaction tx) [0x00070] in <301d14fab821450fa5cc07ec7c940a17>:0
  at Npgsql.NpgsqlConnection.OpenInternal () [0x0012c] in <301d14fab821450fa5cc07ec7c940a17>:0
  at Npgsql.NpgsqlConnection.Open () [0x00000] in <301d14fab821450fa5cc07ec7c940a17>:0
  at FSharp.Data.Sql.Common.Sql.connect[a] (System.Data.IDbConnection con, Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] f) [0x00009] in <5d776594de6dfdbfa74503839465775d>:0
  at FSharp.Data.Sql.Providers.PostgresqlProvider.FSharp-Data-Sql-Common-ISqlProvider-GetColumns (System.Data.IDbConnection con, FSharp.Data.Sql.Schema.Table table) [0x000ae] in <5d776594de6dfdbfa74503839465775d>:0
  at FSharp.Data.Sql.Runtime.SqlDataContext.FSharp-Data-Sql-Common-ISqlDataContext-CreateEntity (System.String tableName) [0x0001f] in <5d776594de6dfdbfa74503839465775d>:0
  at Program.createPerson (System.Object ctx) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:22
  at [email protected] (Microsoft.FSharp.Core.Unit unitVar) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:45
  at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult] (Microsoft.FSharp.Control.AsyncActivation`1[T] ctxt, TResult result1, Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] part2) [0x00005] in <039b17603f7a807e0eeaa652dc64c784>:0
  at Program+withTransaction@16-4[a].Invoke (Microsoft.FSharp.Control.AsyncActivation`1[T] ctxt) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:16
  at Microsoft.FSharp.Control.Trampoline.Execute (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] firstAction) [0x00020] in <039b17603f7a807e0eeaa652dc64c784>:0
--- End of stack trace from previous location where exception was thrown ---

  at Microsoft.FSharp.Control.AsyncResult`1[T].Commit () [0x0002c] in <039b17603f7a807e0eeaa652dc64c784>:0
  at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInCurrentThread[a] (System.Threading.CancellationToken cancellationToken, Microsoft.FSharp.Control.FSharpAsync`1[T] computation) [0x00028] in <039b17603f7a807e0eeaa652dc64c784>:0
  at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T] (System.Threading.CancellationToken cancellationToken, Microsoft.FSharp.Control.FSharpAsync`1[T] computation, Microsoft.FSharp.Core.FSharpOption`1[T] timeout) [0x00013] in <039b17603f7a807e0eeaa652dc64c784>:0
  at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T] (Microsoft.FSharp.Control.FSharpAsync`1[T] computation, Microsoft.FSharp.Core.FSharpOption`1[T] timeout, Microsoft.FSharp.Core.FSharpOption`1[T] cancellationToken) [0x0006e] in <039b17603f7a807e0eeaa652dc64c784>:0
  at Program.main (System.String[] argv) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:52

任何和所有帮助将不胜感激。

f# mono npgsql type-providers
1个回答
0
投票

Async/await 可能返回到一个新线程,也可能返回到同一个线程。因此,这破坏了旧的 .NET Framework 事务,这些事务不再通过线程继续进行。因此,在 .NET 4.5.1 中,他们创建了一个选项

Transactions.TransactionScope(Transactions.TransactionScopeAsyncFlowOption.Enabled)
来支持跨多个线程的事务。遗憾的是,该选项从未在 Mono 中正确实现(只是出于兼容性原因复制了参数)。那时的焦点已经是 .NET Core。

因此,为了保持其可靠性,不要在 Mono 上使用 Async(至少不在生产环境中)。

  • 使用新版本的.NET(Core/5/6/7/8...)
  • ...或者,如果您使用 .NET Framework,请继续使用 Windows。
  • ...或者如果你绝对想使用 Mono,那么就不要使用 async。
© www.soinside.com 2019 - 2024. All rights reserved.