一个实体(比如一个UserEntity)对它的属性有严格的规则,它可以存在于两个状态 - 持久化(这意味着它有一个id
)和预先持久化(这意味着它没有还是id
。
根据this question about how to handle required properties的答案,只有在传递给构造函数的id
时才能创建“真正的”UserEntity。
但是,当我需要根据浏览器发送的信息创建new UserEntity
时,我需要能够在持久保存到数据库之前验证信息。
在过去,我只是创建一个空白的UserEntity(没有id
),设置新属性,然后验证它 - 但是,在这个新的,更安全的方式来思考实体,我不应该没有id
创建一个新的UserEntity。
我不想创建知道如何验证我的UserEntity属性的两个地方,因为如果他们改变(并且他们会),它将是更新代码的两倍,并使错误的机会增加一倍。
如何有效地集中实体属性的验证知识?
注意
我的一个想法是in this question,其中我考虑将非状态属性(如电子邮件,密码和名称)存储在标准化值对象中,该对象将了解其属性的规则,即不同的服务,如Controller,Validator和Repo,或Mapper可以使用。
答案 0 :(得分:4)
这就是工厂的用途。对于工厂方法,您只传递强制UserEntity的真实不变量所需的数据(花一些时间来弄清楚你的真正的 UserEntity的不变量是什么,你最好用你的域做到这一点专家)。
在工厂方法中,您创建一个新的Id并将其传递给UserEntity构造函数。
在这个阶段,如果构造函数中的验证失败,我认为丢弃实例并不是那么糟糕。在最糟糕的情况下 - 你已经失去了一个id ...这不是一个经常发生的情况 - 大部分时间都应该在客户端验证数据。
当然另一个选择是在工厂方法中首先验证参数,然后创建一个新的Id并将其传递给UserEntity构造函数。
答案 1 :(得分:2)
我认为你有几个选择可以考虑:
(1)考虑你的第一个评论:
实体(比如说UserEntity)有严格的规则 属性,它可以存在于两种状态 - 持久化(这意味着它) 有一个id)和pre-persisted(这意味着它还没有id)。
在这里,您已经提到验证实际上取决于实体是否已被持久化。换句话说,如果实体没有被持久化,那么应该在没有ID的情况下有效。如果你继续这个域规范,我觉得验证应该相应地行动(例如,如果对象没有被持久化,即使没有ID也返回isValid)
(2)如果您认为“有效”表示对象具有ID,则您需要在创建时生成ID。根据您的ID生成方式,这可能会变得棘手(例如,保存到数据库并返回创建的ID,或以某种方式生成唯一标识符,或者......)
使用这两种方法,它可能值得为您的实体实现公共基类(例如,使用ID),以帮助最小化跨不同状态的重复验证。希望这也可以保护派生实体免受常见验证的影响。
答案 2 :(得分:0)
在我看来,save()和load()方法应该同时进行验证和设置ID属性。顺便说一下,没有Identity属性的实体根本就不是实体。
在我看来,身份属性应该在实体传输时得到验证和确保,例如
从db加载,从文件加载或(之后)保存到db,以便
如果从db加载失败,则保存到db / file的实体将无法丢弃该实体。
由于验证是业务日志/行为等,因此更好的模式将是
策略模式(http://en.wikipedia.org/wiki/Strategy_pattern)
答案 3 :(得分:0)
如何正确进行验证的主题有些灰色。
验证通常被转换为Invariant和Contextual验证。不变验证适用于那些根据您的问题域必须存在的事项,以便您的模型在其预期角色中正常运行。上下文验证属于在给定使用上下文中有效的状态(例如,用于发送电子邮件的联系人需要电子邮件地址,但不需要电话号码;用于目录邮件的联系人需要邮寄地址,但不需要电子邮件等等。)。
如果您希望在架构上保持纯粹,那么从技术上讲,输入验证的关注点(您的客户在用户界面中键入的内容)和给定实体的状态是两个不同的问题。理想情况下,您的域应该不知道它所编写的特定应用程序类型,因此不应该在向用户显示错误消息时提供适合直接或间接使用的错误消息。这提出了一个问题,因为它可能导致重复或三重错误检查(客户端,服务端,域级),因此许多人选择更实用的方法来处理实体外部的大多数验证(例如验证)实体创建之前的输入模型。)
答案 4 :(得分:-1)
我没有看到持久存在无效数据的问题。有效与否是商业问题,有时可能取决于具体情况。数据库不关心这些业务规则。
如果我必须在网上填写一份大表格并且最后一步要求我输入我的信用卡信息并且我没有准备好我的卡,我将不得不丢弃所有这些信息,并在下次输入它一遍又一遍(这不会发生,因为我宁愿去其他地方)。我希望该应用程序存储我已经提供的信息,稍后我可以使它在功能上有效。只要它无效,我就不能在线订购。