gpt4 book ai didi

entity-framework - 在 RavenDB 集合中存储/查询多种类型的最佳方法是什么?

转载 作者:行者123 更新时间:2023-12-04 07:57:28 24 4
gpt4 key购买 nike

我正在设计一个日志系统,将其日志条目存储在 RavenDB 中,对于这个特定系统,我想存储(以及稍后查询)具有基于所记录事件类型的不同数据结构的文档。考虑我可能想要记录的以下事件:

  • 用户登录 - 存储用户 ID
  • 用户删除文件 - 存储用户 ID 和正在删除的文件名

  • 我有几种不同的方式可以去这里......

    选项 A. 创建两种完全不同的类型
    class LoginEvent
    {
    public int UserId { get; set; }
    }

    class FileDeleteEvent
    {
    public int UserId { get; set; }
    public string Filename { get; set; }
    }

    这种方法会在 RavenDB 中产生两个不同的集合,它们很容易查询。然而,检索所有日志条目的联合需要多次查询和多次往返服务器——一次用于 LoginEvents,第二次用于 FileDeleteEvents。只有两种事件类型并没有太大区别,但随着事件类型数量的增加,问题会变得更糟。

    选项 B. 创建一个基类并从中派生
    abstract class Event
    {
    }

    class LoginEvent : Event
    {
    public int UserId { get; set; }
    }

    class FileDeleteEvent : Event
    {
    public int UserId { get; set; }
    public string Filename { get; set; }
    }

    我尝试过这种方法,但 RavenDB 似乎是按实际类型而不是强制类型来存储和查询文档——当我这样做时 Query<Event>().ToArray()我得到了零结果。为了取回文档,我必须查询它们各自的类型,这实际上相当于上面的选项 A。

    选项 C. 创建不同的属性类
    enum EventType { Login, FileDelete }

    class Event
    {
    public EventType EventType { get; set; }
    public object Info { get; set; }
    }

    class LoginInfo
    {
    public int UserId { get; set; }
    }

    class FileDeleteInfo
    {
    public int UserId { get; set; }
    public string Filename { get; set; }
    }

    使用这种方法,我们总是存储一个 Event 类型的条目,但我们使用相应的 Info 类填充其 Info 属性,该类提供特定于事件类型的详细信息。起初,这个选项似乎是最好的,因为它将所有日志条目存储在单个事件集合中,并使查询完整集合变得容易。但是,假设我只想要文件名为“test.txt”的 FileDelete 事件。这变得有点棘手。

    例如,下面会抛出一个关于“文件名”字段未被索引的有点模糊的错误:
    var events = session.Query<Event>()
    .Where(a => a.EventType == EventType.FileDelete)
    .Where(a => ((FileDeleteInfo)a.Info).Filename == "test.txt")
    .ToArray();

    以下,除了不是我想要的,返回零结果:
    var events = session.Query<Event>()
    .Select(a => a.Info)
    .OfType<FileDeleteInfo>()
    .Where(a => a.Filename == "test.txt")
    .ToArray();

    事实上,下面的投影,根据文档支持的操作,甚至没有返回预期的类型,只是一堆没有意义的奇怪的中间结果:
    var events = session.Query<Event>()
    .Select(a => a.Info)
    .ToArray();

    因此,虽然这个选项从数据存储的角度来看可能是好的,但从可查询性的角度来看却失败了。 (假设我正在构建正确的查询 - 可能还有另一种我没有考虑的方式)。

    选项 D. 创建一个具有所有可能属性的巨型事件类
    enum EventType { Login, FileDelete }

    class Event
    {
    public EventType EventType { get; set; }
    public int UserId { get; set; }
    public string Filename { get; set; }
    .
    .
    .
    }

    这种方法虽然从存储的角度来看有点浪费,但从可查询性的角度来看是微不足道的。当您开始添加更多类型的要记录的事件时会出现问题 - 然后属性的数量开始增加。

    选项 E. 忘记 RavenDB 并使用 Entity Framework + Sql

    我可以相当简单地做到这一点,并使用 EF 的 table-per 继承模式有效地查询。这种方法的缺点是 Sql 对于这个问题来说是严重的矫枉过正——我们不需要关系系统提供的数据一致性和其他严格性。而且,根据我的经验,Sql 插入比将文档存储到 RavenDB(日志系统的一个重要考虑因素)要慢得多。

    所以,有选择......你怎么看?有什么我错过的吗?

    可能相关: Specifying Collection Name in RavenDB

    最佳答案

    解决这个问题的“官方”方法似乎是多态索引:https://ravendb.net/docs/article-page/3.0/csharp/indexes/indexing-polymorphic-data

    这是详细讨论这种方法的博客条目:http://www.philliphaydon.com/2011/12/14/ravendb-inheritance-revisited/

    这里还有一个视频:http://youtu.be/uk2TVs-d6sg

    关于entity-framework - 在 RavenDB 集合中存储/查询多种类型的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9441831/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com