Skip to content

Commit aaf510a

Browse files
committed
Async individuals support #845
1 parent 62cbcc0 commit aaf510a

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

src/SQLProvider.Common/SqlRuntime.Common.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ and ISqlDataContext =
548548
abstract CallSprocAsync : RunTimeSprocDefinition * QueryParameter[] * obj[] -> System.Threading.Tasks.Task<SqlEntity>
549549
/// Get individual row. Takes tablename and id.
550550
abstract GetIndividual : string * obj -> SqlEntity
551+
/// Get individual row asynchronously. Takes tablename and id.
552+
abstract GetIndividualAsync : string * obj -> System.Threading.Tasks.Task<SqlEntity>
551553
/// Save entity to database.
552554
abstract SubmitChangedEntity : SqlEntity -> unit
553555
/// Save database-changes in a transaction to database.
@@ -1229,6 +1231,7 @@ module public OfflineTools =
12291231
| false, _ ->
12301232
failwith ("Add table to dummydata: " + pe)
12311233
member this.GetIndividual(arg1: string, arg2: obj): SqlEntity = raise (System.NotImplementedException())
1234+
member this.GetIndividualAsync(arg1: string, arg2: obj): System.Threading.Tasks.Task<SqlEntity> = raise (System.NotImplementedException())
12321235
member this.GetPendingEntities(): SqlEntity list = (CommonTasks.sortEntities pendingChanges) |> Seq.toList
12331236
member this.GetPrimaryKeyDefinition(arg1: string): string = ""
12341237
member this.ReadEntities(arg1: string, arg2: FSharp.Data.Sql.Schema.ColumnLookup, arg3: Data.IDataReader): SqlEntity array = raise (System.NotImplementedException())

src/SQLProvider.DesignTime/SqlDesignTime.fs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,25 @@ module DesignTimeUtils =
240240
, getterCode = getterCode
241241
)
242242
)
243-
|> Array.append( propertyMap |> Map.toArray |> Array.map (snd >> snd))
243+
244+
// Add async method to fetch individual by primary key
245+
let tableName = table.FullName
246+
let pkColumn = columns.[pkName]
247+
let pkType = Utilities.getType pkColumn.TypeMapping.ClrType
248+
let returnType = typedefof<System.Threading.Tasks.Task<_>>.MakeGenericType(tableTypeDef)
249+
let getAsyncMethod =
250+
ProvidedMethod("GetAsync", [ProvidedParameter("id", pkType)], returnType, invokeCode = fun args ->
251+
let a0 = args.[0]
252+
let pkValue = args.[1]
253+
<@@ ((%%a0 : obj) :?> ISqlDataContext).GetIndividualAsync(tableName, %%pkValue) @@>
254+
)
255+
getAsyncMethod.AddXmlDoc(sprintf "<summary>Asynchronously get an individual %s by primary key value</summary>" table.Name)
256+
257+
seq {
258+
yield getAsyncMethod :> MemberInfo
259+
yield! props |> Seq.cast<MemberInfo>
260+
yield! propertyMap |> Map.toSeq |> Seq.map (snd >> snd) |> Seq.cast<MemberInfo>
261+
} |> Seq.toList
244262

245263
propertyMap
246264
|> Map.toSeq

src/SQLProvider.Runtime/SqlRuntime.DataContext.fs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,37 @@ type public SqlDataContext (typeName, connectionString:string, providerType:Data
236236
if provider.CloseConnectionAfterQuery then con.Close()
237237
entity
238238

239+
member this.GetIndividualAsync(table,id) =
240+
task {
241+
use con = provider.CreateConnection(connectionString) :?> System.Data.Common.DbConnection
242+
let table = Table.FromFullName table
243+
// this line is to ensure the columns for the table have been retrieved and therefore
244+
// its primary key exists in the lookup
245+
let columns = provider.GetColumns(con, table)
246+
let pk =
247+
match provider.GetPrimaryKey table with
248+
| Some v -> columns.[v]
249+
| None ->
250+
// this fail case should not really be possible unless the runtime database is different to the design-time one
251+
failwithf "Primary key could not be found on object %s. Individuals only supported on objects with a single primary key." table.FullName
252+
use com = provider.CreateCommand(con,provider.GetIndividualQueryText(table,pk.Name)) :?> System.Data.Common.DbCommand
253+
if commandTimeout.IsSome then
254+
com.CommandTimeout <- commandTimeout.Value
255+
//todo: establish pk SQL data type
256+
com.Parameters.Add (provider.CreateCommandParameter(QueryParameter.Create("@id", 0, pk.TypeMapping),id)) |> ignore
257+
if con.State <> ConnectionState.Open then
258+
do! con.OpenAsync()
259+
if con.State <> ConnectionState.Open then // Just ensure, as not all the providers seems to work so great with OpenAsync.
260+
if con.State <> ConnectionState.Closed && provider.CloseConnectionAfterQuery then con.Close()
261+
con.Open()
262+
use! reader = com.ExecuteReaderAsync()
263+
let! entities = (this :> ISqlDataContext).ReadEntitiesAsync(table.FullName, columns, reader)
264+
let entity = entities |> Seq.exactlyOne
265+
reader.Close()
266+
if provider.CloseConnectionAfterQuery then con.Close()
267+
return entity
268+
}
269+
239270
member this.ReadEntities(name: string, columns: ColumnLookup, reader: IDataReader) =
240271
[| while reader.Read() do
241272
let e = SqlEntity(this, name, columns, reader.FieldCount)

0 commit comments

Comments
 (0)