postgresqlf#type-providers

F# SqlProvider: System.Exception: Error - you cannot update an entity that does not have a primary key. (public.users)


I'm using the SQLProvider type-provider project: https://fsprojects.github.io/SQLProvider/

As the documentation states on CRUD usage, I'm trying to update a row like this:

   let UpdateGpsLocation(gpsLocationDetails: UpdateGpsLocation) =
        let ctx = SQL.GetDataContext()

        let maybeFoundUser =
            query {
                for user in ctx.Public.Users do
                    where(user.UserId = gpsLocationDetails.UserId)
                    select(Some user)
                    exactlyOneOrDefault
            }

        match maybeFoundUser with
        | Some user ->
            user.GpsLatitude <- Some gpsLocationDetails.Latitude
            user.GpsLongitude <- Some gpsLocationDetails.Longitude
            ctx.SubmitUpdates()
        | None -> failwithf "User %i not found" gpsLocationDetails.UserId

But it is failing with this:

  System.Exception: Error - you cannot update an entity that does not have a primary key. (public.users)
     at FSharp.Data.Sql.Providers.PostgresqlProvider.createUpdateCommand(IDbConnection con, StringBuilder sb, SqlEntity entity, FSharpList`1 changedColumns)
     at <StartupCode$FSharp-Data-SqlProvider>.$Providers.Postgresql.FSharp-Data-Sql-Common-ISqlProvider-ProcessUpdates@1205-8.Invoke(SqlEntity e)
     at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source) in D:\a\_work\1\s\src\fsharp\FSharp.Core\seq.fs:line 497
     at FSharp.Data.Sql.Providers.PostgresqlProvider.FSharp-Data-Sql-Common-ISqlProvider-ProcessUpdates(IDbConnection con, ConcurrentDictionary`2 entities, TransactionOptions transactionOptions, FSharpOption`1 timeout)
     at <StartupCode$FSharp-Data-SqlProvider>.$SqlRuntime.DataContext.FSharp-Data-Sql-Common-ISqlDataContext-SubmitPendingChanges@110.Invoke(Unit unitVar0)
     at FSharp.Data.Sql.Runtime.SqlDataContext.FSharp-Data-Sql-Common-ISqlDataContext-SubmitPendingChanges()
     at BackendDataLayer.Access.UpdateGpsLocation(UpdateGpsLocation gpsLocationDetails) in C:\Users\knocte\Documents\Code\RunIntoMeMASTER\src\BackendDataLayer\Access.fs:line 34

But the table has a primary key! In particular, it's using the SERIAL feature of PostgreSQL, this way:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY
    , gps_latitude FLOAT8
    , gps_longitude FLOAT8
);

Is this a bug in SqlProvider project? Or maybe just in its PostgreSQL component?


Solution

  • I was able to reproduce this problem, there seems to be an issue with using user_id as the column name here.

    This is just a workaround but changing the column name to "UserId" (double-quotes included!) fixed the issue for me.

    See the new schema:

    CREATE TABLE "Users" (
        "UserId" SERIAL PRIMARY KEY
        , "GpsLatitude" FLOAT8
        , "GpsLongitude" FLOAT8
    );
    

    (If you don't use the double-quotes, it will convert UserId into Userid and your F# code won't compile.)