【发布时间】:2009-04-01 00:48:47
【问题描述】:
我有一个像这样的存储库数据访问模式:
IRepository<T>
{
.. query members ..
void Add(T item);
void Remove(T item);
void SaveChanges();
}
想象一下我有一个用户存储库的场景,用户有一个唯一的用户名,如果我创建一个用户名存在的新用户(想象我有一个不检查的哑 ui 层),当我将它添加到存储库中,一切都很好.. 当我点击 SaveChanges 时,我的存储库尝试将项目保存到数据库中,我的数据库幸运地执行了这些规则,并且由于唯一键违规而将我抛出异常中止。
在我看来,通常这种验证是在存储库之上的层完成的,调用它的层知道他们应该确保这个规则,并且会预先检查和执行(希望在某种事务范围内避免种族,但在存在中等无知的情况下似乎并不总是可能的)。
我的存储库不应该执行这些规则吗?如果我的媒介是愚蠢的,例如没有任何完整性检查的平面数据库,会发生什么?
如果存储库正在验证这类事情,他们将如何以调用者可以准确识别问题所在的方式通知调用者违规行为,异常似乎是一种糟糕的处理方式,因为它们相对昂贵且很难专门针对特定的违规行为..
我一直在玩“Can”模式,例如.. CanAdd 和 Add,如果 can 返回冲突,add 将调用 CanAdd 并抛出无效操作异常。. CanAdd 还返回关于什么的冲突列表出错了..这样我可以开始通过堆栈堆叠这些例程..例如,上面的服务层也将有一个“Can”方法,该方法将返回存储库报告+它想要检查的任何其他违规行为(例如更复杂的业务规则,例如哪些用户可以调用特定的操作)。
数据验证是如此基础,但我觉得对于如何可靠地处理更高级的验证要求没有真正的指导。
编辑,另外在这种情况下,您如何处理存储库中实体的验证并通过更改跟踪进行更新。例如:
using (var repo = ...)
{
var user = repo.GetUser('user_b');
user.Username = 'user_a';
repo.SaveChanges(); // boom!
}
正如您所想象的,这将导致异常.. 深入兔子洞,想象一下当我添加用户时我已经有了一个验证系统,然后我做了这样的事情:
using (var repo = ...)
{
var newUser = new User('user_c');
repo.Add(newUser); // so far so good.
var otherUser = repo.GetUser('user_b');
otherUser.Username = 'user_c';
repo.SaveChanges(); // boom!
}
在这种情况下,在添加用户时进行验证是没有意义的,因为“下游”操作无论如何都会把我们搞砸,添加验证规则需要检查实际的持久性存储以及排队等待持久化的任何项目。
这仍然不能阻止之前的更改跟踪问题.. 那么现在我要开始验证保存更改调用了吗?看起来显然不相关的行为可能会发生大量违规行为。
也许我要求的是一个不切实际的完美安全网?
提前致谢, 斯蒂芬。
【问题讨论】:
标签: validation