【问题标题】:Primitive Obsession - Strongly typed int ID with auto incrementPrimitive Obsession - 具有自动增量的强类型 int ID
【发布时间】:2020-02-25 23:43:51
【问题描述】:

如何获得强类型的Id...

public sealed class FileUploadId
{
    public int Value { get; }

    public FileUploadId(int value)
    {
        Value = value;
    }
}

...在我的FileUpload 类中使用...

public class FileUpload : EntityBase, IAggregateRoot
{
    private FileUpload() { /* Required by EF */ }

    public FileUpload(string name, string relativePath, FileUploadType type, string contentType, long? size = null)
    {
        /* Guard clauses... */

        Id = new FileUploadId(0);

        /* Other properties... */
    }

    public FileUploadId Id { get; }

    /* Other properties... */
}

...使用身份(int 自动递增)?

我在TypeConifiguration 中尝试了ValueGeneratedOnAdd(),但没有成功...

public class FileUploadTypeConfig : IEntityTypeConfiguration<FileUpload>
{
    public void Configure(EntityTypeBuilder<FileUpload> builder)
    {
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Id).HasConversion(x => x.Value, x => new FileUploadId(x)).ValueGeneratedOnAdd();

        /* Other configurations... */
    }
}

我知道 HiLo 算法还有另一种选择。但我想让它使用默认的int id 增量。这有可能吗?

【问题讨论】:

  • 为什么你认为你仍然需要FileUploadId 类?如果它所做的只是公开一个只读 int 属性,为什么不在 FileUpload 类上使用一个只读 int 属性呢? FileUploadId 有什么好处?
  • 这是关于“原始痴迷”的。你可以在这里阅读:andrewlock.net/…
  • 谢谢,因为你,我今天学到了一些新东西!然而,我确实认为,虽然博客文章中提出的观点是有效的,并且提出的解决方案也是有效的,但这种方法在许多情况下可能是一种巨大的矫枉过正。
  • 是的,我完全同意。在大多数情况下,这种方法是矫枉过正的。但是,当您从头开始一个包含大型业务领域的新项目时,它可能对干净的代码库非常有帮助。
  • 所以想法是在自定义类中包含一些原始值,例如主键和外键,因此类匹配可以询问您“为什么要尝试将 CustomerID 分配给 OrderID 字段/属性?”有趣的想法。可以适当地为它制作一个通用的。

标签: c# sql-server .net-core entity-framework-core domain-driven-design


【解决方案1】:

我设法通过以下方式获得具有自动递增整数的强类型 ID,可用于 .net6 和 EFCore6:

  • 配置.HasConversion()
  • 添加.ValueGeneratedOnAdd()
  • 添加.Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore)
  • 确保强类型 id 永远不会为空

编辑: 这种方法有一个陷阱。

这与更改跟踪有关。从 ef core 3.0 和 this GitHub issue 开始,当您对键使用自动递增且键值不是默认值时,实体将以“已修改”状态而不是“已添加”状态添加。这是当前解决方案的一个问题,因为我们从未为强类型 ID 设置 null。我们必须手动开始跟踪处于“已添加”状态的实体(使用 DbContext Add 方法),其他类型的自动跟踪将不起作用(例如,将实体添加到导航属性集合中以实现一对多关系)。正在通过this GitHub issue 跟踪对此的官方支持。

【讨论】:

    【解决方案2】:

    老实说,在 EF 中使用带有 SQL 的强类型变量是一种真正的痛苦。我看到的最好的解释可以在this blog post by Andrew Lock找到。

    问题的核心?使用强类型值会导致在客户端执行查询过滤(WHERE ID = value 子句),要求进程从数据库中检索所有记录以在本地执行选择。

    解决方案的核心是什么?使用 ValueConverter 将强类型值转换为正确的 SQL Server 值。

    细节很丰富。有关如何执行此操作的详细信息,请参阅参考文章。

    【讨论】:

    • 这实际上并没有解决我的问题。我的问题不是将强类型值转换为本地人。我已经知道 Andrews 博客系列。但他总是使用手动生成的Guid。我只想使用一个int,它是自动递增(插入之前不是手动创建的)。
    【解决方案3】:

    我建议不要让 EF 处理强类型 ID。它不能很好地处理它,并且在某些情况下它会尝试过滤内存中的内容。

    但是您可以同时拥有这两个属性,一个用于 EF 查询,一个用于其他所有属性。

    class FileUpload
    {
        public int InternalId { get; private set; }
        public FileUploadId Id 
        {
            get { return new FileUploadId(InternalId); }
            set { InternalId = value.Value; }
        }
    }
    

    它是泄漏的,但它有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-22
      • 2021-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 1970-01-01
      • 2016-10-31
      相关资源
      最近更新 更多