领域实体是否应该全部加载?

时间:2011-03-01 16:32:02

标签: domain-driven-design entities aggregates

我有一个自定义ASP.NET成员资格提供程序,我正在尝试添加密码历史记录功能。用户的密码在X天后过期。然后他们必须将密码更改为在过去的X更改中未使用过的密码。

我已经有了User实体,它的当前密码有一个密码属性。这将映射到db中的User表。由于我需要一个以前密码的列表,因此我创建了一个UserPassword表来存储此信息,其中包含对UserId的FK引用。

由于密码是值对象,并且在用户之外没有任何意义,因此它们属于User聚合内部,以User为根。但这就是我的困境。当我从存储库中检索用户时,我是否始终必须获取以前使用过的所有密码? 99%的时间我不关心他们的旧密码,所以每次我需要一个用户实体时检索它们对于db性能来说似乎是一件蠢事。我无法使用延迟加载,因为User实体与上下文断开连接。

我正在考虑创建一个PasswordHistory实体,但由于上述原因,密码并不是真正的实体。

你们DDD专家怎么处理这种情况?

感谢。

编辑1:在考虑了这个之后,我意识到这实际上是一个关于延迟加载的问题。更具体地说,如何处理断开连接的实体中的延迟加载?

编辑2:我正在使用LINQ to SQL。使用CodePlex中的this将实体与上下文完全分离。

1 个答案:

答案 0 :(得分:0)

很难完全回答这个问题,因为你没有指定一个平台,所以我无法确定你所谓的“断开连接”是什么意思。 Hibernate“已断开连接”意味着您在有效会话中有一个对象,但数据库连接当前未打开。这是微不足道的,你只需重新连接和延迟加载。更复杂的情况是你有一个“分离”的对象,即根本不再与活动会话相关联,在这种情况下,你不能简单地重新连接,你必须得到一个新对象或附加你拥有的对象。积极的会议。

无论哪种方式,即使在更复杂的场景中,仍然没有很多延迟加载策略,因为要求是如此不灵活:你必须“连接”加载任何东西,懒惰或其他。期。我将假设“断开连接”意味着与分离相同的事情。您的策略归结为两种基本方案:这种情况您可能需要在运行时重新连接/连接到延迟加载,或者是您希望在断开连接之前决定有时有条件地加载其他对象的情况首先是什么?

有时候你可能需要为两种可能性编码。

在您的情况下,您还必须连接不仅是延迟加载旧密码,而是首先更新User对象。此外,由于这是ASP.NET,您可能正在使用每个请求的会话,在这种情况下,您的选项现在基本上只有一个 - 在断开连接之前有条件地延迟加载,这是关于它。

最常见的情况是一个人登录,系统确定他们需要更改密码,并要求他们在继续之前这样做。在这种情况下,您也可以在登录后立即处理并保持用户连接。但是您可能正在使用每个请求的会话,所以您可以做的是在第一个请求过程中的时间限制,如果它已过期,您仍然在这里连接,所以继续并返回一个满载的用户(假设您正在使用历史某种客户端脚本验证中的密码)。然后在提交行程中,您可以重新附加或只获取一个新的User实例并更新它。

然后总是有可能您必须随时为他们提供更改密码的选项。他们已经登录了。在这里没什么关系,你有一个用户,但请求很久以前就结束了,并且没有加载密码。在这里,我可能只是编写一个服务方法,当他们调用更改密码函数时,服务获取User对象的第二个副本,其中包含完整的历史记录仅用于更新,然后更新密码,然后丢弃该对象,甚至没有将其用于会话或身份验证目的。或者,如果您在每个请求中使用Session,则必须执行等效操作 - 获取完全初始化的对象以进行客户端验证,然后在提交数据时,您可以重新连接已有的数据或者实际获得第三个实例做更新。

如果在开始经过身份验证的会话后需要密码,您仍然可以执行相同的操作,也可以替换本地用户或更新本地用户的内存密码版本。

如果你有太多的事情继续进行多级身份验证,那么你很可能不得不要求他们注销并在密码更改后进行完全重新登录,因此用户的状态无关紧要一旦他们要求更改密码,就会很多。

在任何情况下,如果您正在使用每个请求的会话,并且您的对象在每次请求后都会完全分离,那么在第一个场景中,当您在原始请求上的服务器上时,您仍然可以延迟加载以返回客户端验证的数据。在第二种情况下,你必须再做一次旅行(这里确实没有延迟加载这样的事情)。在这两种情况下,您都必须权衡两个更新选项,因为在更新之前总是断开连接。您可以在提交行程中从数据库中获取第二个实例进行更新,也可以重新附加已有的实例。这取决于什么是最优/最简单的 - 为一个不寻常的事件保存数据包往返真的很重要吗?使用您选择的ORM重新连接是否可能再次访问数据库?我可能不会费心去重新连接,而只是在我需要的时候获得实际更新的新实例。