【问题标题】:How to manage unicity in my buisness logic layer?如何在我的业务逻辑层管理单一性?
【发布时间】:2019-04-20 22:55:58
【问题描述】:

在 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 方法在添加之前确保我的应用程序中的所有 Foo 属性代码都是唯一的。

我尽我所能尊重坚持无知原则,但我并不像我希望的那样熟练。

对于初学者来说,确定 Code 字段是否唯一是 Builder 的角色吗?

其次,我知道在我的验证层中,我可以确定是否存在现有的 foo,其代码与我当前尝试添加的实际 foo 相同。但是这种方法不是线程安全的或事务性的。

事实是我不想等待我添加我的 foo 的那一刻也有一个 SqlException,只是知道它不能完成。

使用 牢记快速失败原则。

【问题讨论】:

  • 除非您正在构建一个单用户系统,否则 no 数量的预检查可能会有所帮助,因为其他人可能 关于 插入重复的项目并且在您完成预检查和执行 实际 插入之间取得成功。你必须处理这个异常无论如何。为什么要添加更多代码/层。
  • @Damien_The_Unbeliever,我知道你在说什么,我只是希望有另一种方法来处理这个问题。而 SqlException 对原因也不是很友好。 (必须阅读 sql 结果代码......一种神奇的数字......)。

标签: c# design-patterns .net-core architecture ef-core-2.2


【解决方案1】:

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

让我们问几个关于这个代码的性质和它代表什么的问题

  1. 谁负责代码生成:系统的用户还是系统本身?

  2. 代码能否完全随机(例如 UUID)?

  3. 是某种特殊算法生成的代码(SSN或者可能是由具有特殊含义的不同部分组成的CarPartNumber

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

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

如果问题 2 的答案是“是”,那么您没有问题。您可以拥有重复的 UUID,但机会非常低。您可以在数据库中添加 Unique Constrant 以防万一,并将此违规视为您不关心的正常错误,因为它每百万年就会发生一次。

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

如果您选择使用锁,您可以锁定整个资源 Foo 或只锁定 Code 生成。

选项 1

您必须处理 SQLException。今天在大多数应用程序中都使用这个,因为它不会因为有人锁定资源而导致应用程序长时间停止,从而确保流畅的用户体验

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

选项2

有时您确实需要确保没有并发,因此您使用此选项。在这种情况下,您将不得不为一个用户锁定 Foo 的创建过程,并且不允许其他用户甚至能够打开对话框/表单/页面来创建 Foo 如果有锁。

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

我有朋友在申请保险时使用了这个锁。通常在他们的申请中,一个人会去一个办公室进行保险。所以同时为同一个人创建保险的可能性非常低,但是为同一个人购买多个保险的成本非常高。

选项 3:

另一方面,如果您的代码是由系统生成的,您可以拥有一个处理代码生成并确保生成唯一代码的CodeGenerationService。您可以对这些请求进行排队。在 Service 中的每一次生成操作中,您都可以检查此代码是否存在并返回错误(或抛出异常)。

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

您仍然可以在此处使用并发,因此会有一个微小的变化,即一个用户将添加一个 Foo,而另一个用户将收到错误“Oooops... 出现错误...请重试”。因为这将在 100 年中发生一次,所以没关系。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 2012-02-05
    • 2011-06-01
    • 2011-12-03
    • 2011-11-26
    • 2017-04-29
    相关资源
    最近更新 更多