Я адаптирую пример Marten в C # для F #, но, как ни странно, не могу действительно получить правильное значение моей агрегации:
open System
open Marten
open Marten.Schema.Identity
type AccountCreation = {
Owner: string
AccountId: Guid
CreatedAt: DateTimeOffset
StartingBalance: decimal
}
type Transaction = {
To: Guid
From: Guid
Description: string
Time: DateTimeOffset
Amount: decimal
}
type AccountEvent =
| AccountCreated of AccountCreation
| AccountCredited of Transaction
| AccountDebited of Transaction
type Account() =
member val Id = Unchecked.defaultof<Guid> with get,set
member val Owner = Unchecked.defaultof<string> with get,set
member val Balance = Unchecked.defaultof<decimal> with get,set
member val CreatedAt = Unchecked.defaultof<DateTimeOffset> with get,set
member val UpdatedAt = Unchecked.defaultof<DateTimeOffset> with get,set
member this.Apply(accountEvent: AccountEvent) =
match accountEvent with
| AccountEvent.AccountCreated accountCreation ->
this.Id <- accountCreation.AccountId
this.Owner <- accountCreation.Owner
this.Balance <- accountCreation.StartingBalance
this.CreatedAt <- accountCreation.CreatedAt
this.UpdatedAt <- accountCreation.CreatedAt
| _ -> ()
[<EntryPoint>]
let main argv =
use store = DocumentStore.For(fun options ->
let connectionString = sprintf "host=%s;database=%s;username=%s;password=%s"
"localhost"
"postgres"
"root"
"root"
options.Connection(connectionString)
options.Events.AddEventType(typeof<AccountEvent>)
options.Events.InlineProjections.AggregateStreamsWith<Account>() |> ignore
)
use session = store.LightweightSession()
let khalidId = CombGuidIdGeneration.NewGuid()
let khalid = AccountEvent.AccountCreated({
Owner = "Khalid Abuhakmeh"
AccountId = khalidId
StartingBalance = 1000m
CreatedAt = DateTimeOffset.UtcNow
})
session.Events.Append(khalidId, khalid) |> ignore
session.SaveChangesAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
let account = session.LoadAsync<Account>(khalidId)
|> Async.AwaitTask
|> Async.RunSynchronously
let stream = session.Events.FetchStream(khalidId)
printfn "%A" account
printfn "%A" stream
0
Проблема заключается в том, что при запросе документа, соответствующего агрегациисо связанным идентификатором он просто возвращает null
let account = session.LoadAsync<Account>(khalidId)
|> Async.AwaitTask
|> Async.RunSynchronously
Любопытно, что поток событий возвращает событие, как и ожидалось:
let stream = session.Events.FetchStream(khalidId)
Как будто проекция никогда не создается и не сохраняетсяследовательно, метод Account
агрегат Apply
никогда не вызывается.
Источник: Мартен - Прогнозы
[РЕДАКТИРОВАТЬ]
ЭтоОказывается, что если я не использую дискриминационные союзы и напрямую тип различных случаев, это работает:
open System
open Marten
open Marten.Schema.Identity
type AccountCreation = {
Owner: string
AccountId: Guid
CreatedAt: DateTimeOffset
StartingBalance: decimal
}
type Transaction = {
To: Guid
From: Guid
Description: string
Time: DateTimeOffset
Amount: decimal
}
type AccountEvent =
| AccountCreated of AccountCreation
| AccountCredited of Transaction
| AccountDebited of Transaction
type Account() =
member val Id = Unchecked.defaultof<Guid> with get,set
member val Owner = Unchecked.defaultof<string> with get,set
member val Balance = Unchecked.defaultof<decimal> with get,set
member val CreatedAt = Unchecked.defaultof<DateTimeOffset> with get,set
member val UpdatedAt = Unchecked.defaultof<DateTimeOffset> with get,set
member this.Apply(accountCreation: AccountCreation) =
this.Id <- accountCreation.AccountId
this.Owner <- accountCreation.Owner
this.Balance <- accountCreation.StartingBalance
this.CreatedAt <- accountCreation.CreatedAt
this.UpdatedAt <- accountCreation.CreatedAt
[<EntryPoint>]
let main argv =
use store = DocumentStore.For(fun options ->
let connectionString = sprintf "host=%s;database=%s;username=%s;password=%s"
"localhost"
"postgres"
"root"
"root"
options.Connection(connectionString)
options.Events.AddEventType(typeof<AccountCreation>)
options.Events.AddEventType(typeof<Transaction>)
options.Events.InlineProjections.AggregateStreamsWith<Account>() |> ignore
)
use session = store.LightweightSession()
let khalidId = CombGuidIdGeneration.NewGuid()
let khalid = {
Owner = "Khalid Abuhakmeh"
AccountId = khalidId
StartingBalance = 1000m
CreatedAt = DateTimeOffset.UtcNow
}
session.Events.Append(khalidId, khalid) |> ignore
session.SaveChangesAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
let account = session.LoadAsync<Account>(khalidId)
|> Async.AwaitTask
|> Async.RunSynchronously
let stream = session.Events.FetchStream(khalidId)
printfn "%A" account
printfn "%A" stream
0
[EDIT] Я открыл проблему на GitHub: https://github.com/JasperFx/marten/issues/1283