如何管理业务逻辑层中的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原则确保我的应用程序中的单一性的最佳方法是什么。

答案

因为没有系统的具体示例或描述,所以我会稍微概括一下。如果您提供具体示例,我可以添加其他信息。每个解决方案都有一个适用于最佳的上下文,当然总是需要权衡

让我们问几个关于本规范的性质及其代表的问题

  1. 谁负责代码生成:系统用户还是系统本身?
  2. 代码可以完全随机(例如UUID)吗?
  3. 代码是由一些特殊的算法生成的(SSN或者是由具有特殊含义的不同部分组成的CarPartNumber

还有一个非常重要的问题:

  1. 我们多久会发生这些独特的违规行为?

如果问题2的答案是肯定的,那么您没有问题。你可以有一个重复的UUID,但机会非常低。为了防万一,您可以向DB添加一个唯一的常量,并将此违规视为您不关心的正常错误,因为它将在每一百万年中发生一次。

如果问题3的答案是肯定的,那么我们就有不同的情况。在多用户系统中,您无法避免并发。有几种方法可以处理这种情况:

如果您选择使用锁,则可以锁定整个资源Foo或仅锁定代码生成。

选项1:

您将不得不处理SQLException。这个在今天的大多数应用程序中使用,因为它可以确保顺畅的用户体验,因为有人锁定了资源,因此不会导致应用程序停滞很长时间。

您可以使用抽象,例如存储库。定义您自己的应用程序级别异常,将由存储库抛出UniqueCodeViolationException。存储库将尝试{} catch {} SQLException,处理它并在比较错误代码时将其包装在UniqueCodeViolationException中。这不会为您节省支票,但至少如果会隐藏具体错误,您将只在一个地方进行处理。

选项2:

有时你真的需要确保没有并发,所以你使用这个选项。在这种情况下,您必须仅为一个用户锁定创建Foo的过程,并且如果存在锁定,则不允许其他人甚至能够打开用于创建Foo的对话框/表单/页面。

这可以确保一致性并通过创建一个基本上不能用于针对同一Foo的多个用户的系统来避免此问题。您正在构建的应用程序很可能只有一个人负责Foo创建,或者并发性很低,因此这可能是一个很好的解决方案。

我有朋友在保险申请中使用这个锁。通常在他们的申请中,一个人去一个办公室做保险。因此,为同一个人创建保险的并发性的可能性非常低,但是向同一个人提供多个保险的成本非常高。

选项3:

另一方面,如果您的代码由系统生成,则可以使用CodeGenerationService处理代码生成并确保生成唯一代码。您可以拥有包含这些请求的队列。在服务中的每个生成操作中,您可以检查此代码是否存在并返回错误(或抛出异常)。

现在回答问题4.如果您不希望经常发生冲突,只需在数据库中添加一个唯一约束并将其视为一般意外错误。添加检查代码是否已存在,如果存在则显示错误。

你仍然可以在这里有一个并发,所以会有一个微小的变化,一个用户将添加一个Foo而另一个将得到一个错误“Oooops ...错误的东西..请再试一次”。因为这将在100年内发生一次,没关系。

最后的解决方案将忽略在极少数情况下可能发生的特殊情况,从而使您的系统更加简单。

以上是关于如何管理业务逻辑层中的unicity?的主要内容,如果未能解决你的问题,请参考以下文章

清晰架构(Clean Architecture)的Go微服务: 事物管理

N 层服务层验证显示表示层中的业务逻辑错误

使用分层实现业务处理

Java Server Faces:仅在业务逻辑层中进行验证

在单独的数据访问和业务逻辑层中,我可以在业务层中使用实体框架类吗?

为啥我们需要在单独的服务层中编写业务逻辑而不是在控制器本身中编写?