该应用的领域很简单,有**Product**和**Category**两个实体以及一个**ProductStockState**枚举,如图所示: ![](https://img.kancloud.cn/18/13/1813193476712abfb7275e8dd4bdc076_1141x604.png) 实体在解决方案的领域层中定义,它分为两个项目: * **.Domain**用于定义您的实体、值对象、领域服务、存储库接口和其他与领域相关的核心类。 * **.Domain.Shared**用于定义一些可用于其他层的共享类型。通常,我们在这里定义枚举和一些常量。 ## 产品类别实体(Category) `Category`实体用于对产品进行分类。*在ProductManagement.Domain*项目中创建一个*Categories*文件夹,并在其中创建一个`Category`类: ``` using System; using Volo.Abp.Domain.Entities.Auditing; namespace ProductManagement.Categories {     public class Category : AuditedAggregateRoot<Guid>     {         public string Name { get; set; }     } } ``` `Category`类派生自`AuditedAggregateRoot<Guid>`,这里`Guid`是实体的主键 (`Id`) 。您可以使用任何类型的主键(例如`int`、`long`或`string`)。 `AggregateRoot`是一种特殊的实体,用于创建聚合的根实体。它是一个**领域驱动设计**(**DDD**) 概念,我们将在接下来的章节中更详细地讨论。 相比`AggregateRoot`类,`AuditedAggregateRoot`添加了更多属性:`CreationTime`、、`CreatorId`、`LastModificationTime`和`LastModifierId`。 当您将实体插入数据库时​​,ABP 会自动给这些属性赋值,`CreationTime`会设置为当前时间,`CreatorId`会自动设置为当前用户的`Id`属性。 **关于充血领域模型** 在本章中,我们使用公共的 getter 和 setter 来保持实体的简单性。如果您想创建更丰富的领域模型并应用 DDD 原则和其他最佳实践,我们将在接下来的章节中讨论它们。 ## 产品库存状态枚举(ProductStockState) `ProductStockState`是一个简单的枚举,用来设置和跟踪产品库存。 我们在\*.Domain.Shared*项目中创建一个*Products\*文件夹和一个枚举`ProductStockState`: ``` namespace ProductManagement.Products {     public enum ProductStockState : byte     {         PreOrder,         InStock,         NotAvailable,         Stopped     } } ``` 我们将在**数据传输对象(DTO)** 和界面层复用该枚举。 ## 产品实体(Product) 在.Domain项目中创建一个*Products*文件夹,并在其中创建一个类`Product`: ``` using System; using Volo.Abp.Domain.Entities.Auditing; using ProductManagement.Categories; namespace ProductManagement.Products {     public class Product : FullAuditedAggregateRoot<Guid>     {         public Category Category { get; set; }         public Guid CategoryId { get; set; }         public string Name { get; set; }         public float Price { get; set; }         public bool IsFreeCargo { get; set; }         public DateTime ReleaseDate { get; set; }         public ProductStockState StockState { get; set; }     } } ``` 这一次,我继承自`FullAuditedAggregateRoot`,相比`Category`d的`AuditedAggregateRoot`类,它还增加了`IsDeleted`、`DeletionTime`和`DeleterId`属性。 `FullAuditedAggregateRoot`实现了`ISoftDelete`接口,用于实体的**软删除**。即它永远不会从数据库中做物理删除,而只是标记为已删除。ABP 会自动处理所有的软删除逻辑。包括下次查询时,已删除的实体会被自动过滤,除非您有意请求它们,否则它不会在查询结果中显示。 >[success] 注:数据过滤系统详情将在\[*第 8 章*\] 进行深入介绍。 ## 导航属性 在这个例子中,`Product.Category`是一个导航属性为`Category`的实体。如果您使用 MongoDB 或想要真正实现 DDD,则不应将导航属性添加到其他聚合中。但是,对于关系数据库,它可以完美运行并为我们的代码提供灵活性。 解决方案中的新文件如图所示: ![](https://img.kancloud.cn/d9/61/d9612e3f89845452ddd70682abd3c252_512x666.png) 我们已经创建了领域对象。接下来是常量值。 ## 常量值 这些常量将在输入验证和数据库映射阶段进行使用。 首先,在.Domain.Shared项目中创建一个 *Categories* 文件夹并在里面添加一个类`CategoryConsts`: ``` namespace ProductManagement.Categories {     public static class CategoryConsts     {         public const int MaxNameLength = 128;     } } ``` 在这里,`MaxNameLength`值将用于`Category`的`Name`属性的约束。 然后,在.Domain.Shard的 *Products* 文件夹中创建一个`ProductConsts`类: ``` namespace ProductManagement.Products {     public static class ProductConsts     {         public const int MaxNameLength = 128;     } } ``` 该`MaxNameLength`值将用于约束`Product`的`Name`属性。 ![](https://img.kancloud.cn/89/58/89588d0ff4f4ba2f7ae7b1648279b044_246x165.png) 现在,领域层已经完成定义,接下来将为 EF Core 配置数据库映射。