如何管理业务逻辑层中的unicity?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何管理业务逻辑层中的unicity?相关的知识,希望对你有一定的参考价值。
在aspnetcore mvc执行上下文中。
我有这个简单的实体。
public class Foo
{
public int Id { get; private set; }
public string Name{ get; private set; }
public string Code { get; private set; }
private Foo() { }
public Foo(string Name, string Code)
{
GuardClauses.IsNullOrWhiteSpace(Name,nameof(Name), "cannot be null or empty");
GuardClauses.IsNullOrWhiteSpace(Code, nameof(Code), "cannot be null or empty");
this.Nom = Nom;
this.Code = Code;
}
}
在我的DbContext中,我有这个代码字段/约束,确保代码从持久性的角度来看是唯一的。
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Foo>()
.HasIndex(u => u.Code)
.IsUnique();
}
我想在我的服务类中使用addNewFoo方法,以确保在添加它之前,对于我的应用程序中的所有Food,属性代码是唯一的。
我尽可能多地尝试尊重持久性无知原则,但我并不像我希望那样熟练。
对于初学者来说,构建器的作用是确定代码字段是否为唯一?
其次,我知道在我的验证层中,我可以确定是否现有的foo已经使用与我正在尝试添加的实际foo相同的代码。但是这个approchah不是线程安全的或事务性的。
事实是我不想等待我添加我的foo的那一刻也有一个SqlException,只是为了知道它无法完成。
使用Fail Fast原则确保我的应用程序中的单一性的最佳方法是什么。
因为没有系统的具体示例或描述,所以我会稍微概括一下。如果您提供具体示例,我可以添加其他信息。每个解决方案都有一个适用于最佳的上下文,当然总是需要权衡
让我们问几个关于本规范的性质及其代表的问题
- 谁负责代码生成:系统用户还是系统本身?
- 代码可以完全随机(例如UUID)吗?
- 代码是由一些特殊的算法生成的(SSN或者是由具有特殊含义的不同部分组成的CarPartNumber)
还有一个非常重要的问题:
- 我们多久会发生这些独特的违规行为?
如果问题2的答案是肯定的,那么您没有问题。你可以有一个重复的UUID,但机会非常低。为了防万一,您可以向DB添加一个唯一的常量,并将此违规视为您不关心的正常错误,因为它将在每一百万年中发生一次。
如果问题3的答案是肯定的,那么我们就有不同的情况。在多用户系统中,您无法避免并发。有几种方法可以处理这种情况:
- 选项1:Optimistic Offline Lock
- 选项2:Pessimistic Offline Lock
- 选项3:如果系统正在生成代码,则具有特殊服务和队列代码生成请求。
如果您选择使用锁,则可以锁定整个资源Foo或仅锁定代码生成。
选项1:
您将不得不处理SQLException。这个在今天的大多数应用程序中使用,因为它可以确保顺畅的用户体验,因为有人锁定了资源,因此不会导致应用程序停滞很长时间。
您可以使用抽象,例如存储库。定义您自己的应用程序级别异常,将由存储库抛出UniqueCodeViolationException。存储库将尝试{} catch {} SQLException,处理它并在比较错误代码时将其包装在UniqueCodeViolationException中。这不会为您节省支票,但至少如果会隐藏具体错误,您将只在一个地方进行处理。
选项2:
有时你真的需要确保没有并发,所以你使用这个选项。在这种情况下,您必须仅为一个用户锁定创建Foo的过程,并且如果存在锁定,则不允许其他人甚至能够打开用于创建Foo的对话框/表单/页面。
这可以确保一致性并通过创建一个基本上不能用于针对同一Foo的多个用户的系统来避免此问题。您正在构建的应用程序很可能只有一个人负责Foo创建,或者并发性很低,因此这可能是一个很好的解决方案。
我有朋友在保险申请中使用这个锁。通常在他们的申请中,一个人去一个办公室做保险。因此,为同一个人创建保险的并发性的可能性非常低,但是向同一个人提供多个保险的成本非常高。
选项3:
另一方面,如果您的代码由系统生成,则可以使用CodeGenerationService处理代码生成并确保生成唯一代码。您可以拥有包含这些请求的队列。在服务中的每个生成操作中,您可以检查此代码是否存在并返回错误(或抛出异常)。
现在回答问题4.如果您不希望经常发生冲突,只需在数据库中添加一个唯一约束并将其视为一般意外错误。添加检查代码是否已存在,如果存在则显示错误。
你仍然可以在这里有一个并发,所以会有一个微小的变化,一个用户将添加一个Foo而另一个将得到一个错误“Oooops ...错误的东西..请再试一次”。因为这将在100年内发生一次,没关系。
最后的解决方案将忽略在极少数情况下可能发生的特殊情况,从而使您的系统更加简单。
以上是关于如何管理业务逻辑层中的unicity?的主要内容,如果未能解决你的问题,请参考以下文章
清晰架构(Clean Architecture)的Go微服务: 事物管理
Java Server Faces:仅在业务逻辑层中进行验证