【发布时间】:2019-06-06 10:10:00
【问题描述】:
我将 Marten 用作事件存储,特别是用于获取事件流。
type AccountCreation = {
Owner: string
AccountId: Guid
CreatedAt: DateTimeOffset
StartingBalance: decimal
}
type AccountEvents =
| AccountCreated of AccountCreation
| AccountCredited of Transaction
| AccountDebited of Transaction
let settings = {
Host = "localhost"
DatabaseName = "postgres"
UserName = "root"
Password = "root"
EventTypes = eventTypes
}
use store = createDocumentStore settings
use session = store.LightweightSession()
let khalidId = Guid.NewGuid()
let billId = Guid.NewGuid()
let khalid = AccountEvents.AccountCreated({
Owner = "Khalid Abuhakmeh"
AccountId = khalidId
StartingBalance = 1000m
CreatedAt = DateTimeOffset.UtcNow
})
let bill = {
Owner = "Bill Boga"
AccountId = billId
StartingBalance = 0m
CreatedAt = DateTimeOffset.UtcNow
}
session.Events.Append(khalidId, khalid) |> ignore
session.Events.Append(billId, bill) |> ignore
session.SaveChanges()
let stream = session.Events.FetchStream()
stream 被IReadOnlyList<IEvent> 和IEvent 定义为:
public interface IEvent
{
Guid Id { get; set; }
int Version { get; set; }
long Sequence { get; set; }
object Data { get; }
Guid StreamId { get; set; }
string StreamKey { get; set; }
DateTimeOffset Timestamp { get; set; }
string TenantId { get; set; }
void Apply<TAggregate>(TAggregate state, IAggregator<TAggregate> aggregator) where TAggregate : class, new();
}
如果Data 属性的基础类型是AccountEvents,我想将每个IEvent 转换为AccountEvents(如果不是,则该项目不会在结果序列中产生)。
在 C# 中,我会简单地使用关键字 as 来实现这一点,但在 F# 中,我不确定什么是最快的 F#-ish 方式(就性能而言)。
我最终得到了以下代码:
let seqCastOption<'T> sequence =
sequence
|> Seq.map(fun x ->
match box x with
| :? 'T as value -> Some value
| _ -> None)
let fetchStream<'T> (session: IDocumentSession) (id: Guid) =
let stream = session.Events.FetchStream(id)
stream
|> Seq.map(fun x -> x.Data)
|> seqCastOption<'T>
|> Seq.filter (fun x -> x.IsSome)
|> Seq.map(fun x -> x.Value)
但这似乎相当“昂贵”,我想知道将.Data 转换为Option<AccountEvents> + 过滤IsSome 的步骤是否可以一次完成。
【问题讨论】:
-
快速和
seq(IEnumerable) 几乎是矛盾的。话虽如此,直接在 F# 中使用 LINQ 通常比使用Seq模块提供更好的性能。为了提高性能Nessos流可能是一个有趣的选择。