【问题标题】:Can I force RavenDB to allow IDocumentSession.Store() to accept an entity with existing id?我可以强制 RavenDB 允许 IDocumentSession.Store() 接受具有现有 ID 的实体吗?
【发布时间】:2013-04-25 14:17:02
【问题描述】:

我有一个应用程序,我正在从 RavenDB 1 升级到 RavenDB 2。该应用程序不直接将其域对象存储在数据库中。相反,域对象在持久化之前被转换为文档对象(读取时反之亦然)。例如,域对象:

public class User {
    public string Id { get; private set; }
    public string Email { get; set; }
    public string PasswordSalt { get; private set; }
    public string PasswordHash { get; private set; }

    public void ChangePassword(string oldPassword, string newPassword) {
        ...
    }
    .
    .
    .
}

以及相应的文档对象(存储在数据库中的内容):

class UserDocument {
    public static UserDocument FromEntity(User user) {
        ...
    }

    public string Id { get; set; }
    public string Email { get; set; }
    public string PasswordSalt { get; set; }
    public string PasswordHash { get; set; }

    public User ToEntity() {
        ...
    }
}

因此,如果我想更改存储在数据库中的用户文档,我通常会加载它,将其转换为相应的域对象,进行更改(例如调用 ChangePassword()),将域对象转换回文档对象,最后调用 IDocumentSession.Store() 和 SaveChanges()。这在 RavenDB 1 中运行良好。

然而,在 RavenDB 2 中,我似乎不允许使用 Id 属性设置为已获取 Id 的实体调用 IDocumentSession.Save()。更新文档时,根据定义,将使用 Id 属性。

这个想法似乎是,在 RavenDB 2 中,我将加载一个对象,对其进行更改,然后调用 SaveChanges(),客户端将跟踪已加载的对象并自动将它们发送到服务器。由于我将在代理对象(域对象)中进行所有更改并且不会将原始文档对象留在内存中,因此这对我来说是不可能的。

是否可以将 RavenDB 配置为使用 RavenDB 1 中存在的行为?

【问题讨论】:

    标签: c# ravendb


    【解决方案1】:

    我们的想法是不要在 User 和 UserDocument 之间进行这种分离。您希望使用 IDocumentSession 将 User 对象存储到 RavenDB 中 - 事实上它们被存储为文档实际上是您应该关注的实现细节。

    在这方面,RavenDB 1 和 2 之间没有任何真正的区别。

    您应该能够做到以下两项之一:

    1. 使用 IDocumentSession.Load(或 Query)重新加载对象,直接更改 Unit-of-Work 并在完成后调用 SaveChanges

    2. 加载对象,将其更改为另一个对象(使用复制构造函数等),然后将新对象存储在相同的 ID 下。你可以通过调用 session.Store(obj, null, id) 来做到这一点。

    【讨论】:

    • 就我个人而言,我更喜欢保持域对象和“文档对象”之间的区别,因为它允许我将域对象的 PasswordHash-setter 设为私有,只允许更改通过 ChangePassword() 方法获取其值。
    • RavenDB 1 和 2 之间发生了一些变化;我的模式在 RavenDB 1 上正常工作,但是 och 2 我得到了上述错误。可能有一种方法可以调用 session.Store(...) 以使其成为 wokd 但我找不到它(这就是我在这里问的原因 ;-) )。不幸的是,您的建议不起作用,因为 Store 的第二个参数是 System.Guid;不可为空的类型。也许你可以解释一下你想用那行代码做什么?
    • 您仍然可以将 setter 设为私有,所有私有属性都已序列化。这种区别没有意义,而且会让你白费力气。我建议的对 Store 的调用应该与 Guid.Empty 一起使用,它的想法是用新提供的对象强制覆盖指定 ID 下的文档。
    • 据我所知,如果不将持久层泄漏到域层,您就不能让 setter 私有。你可能会称我为纯粹主义者,但这就是我滚动的方式(或者我想在这个特定项目上尝试的方式):-)。实际上,使用 Guid.Empty 是行不通的;结果与我刚刚调用 Store(obj) 的结果相同 - 抛出了 NonUniqueObjectException。不过,感谢您提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    相关资源
    最近更新 更多