|
|
// ============================================================================
|
|
|
// 【文件说明】HwPortalSearchDoc.cs - 搜索索引实体类
|
|
|
// ============================================================================
|
|
|
// 这是一个 Entity Framework Core (EF Core) 的实体类,用于存储搜索索引数据。
|
|
|
//
|
|
|
// 【什么是搜索索引?】
|
|
|
// 搜索索引是"读模型"(Read Model),用于优化搜索查询性能:
|
|
|
// 1. 把分散在多个业务表的数据聚合到一个表
|
|
|
// 2. 预处理搜索内容(如拼接标题、正文)
|
|
|
// 3. 建立索引加速查询
|
|
|
//
|
|
|
// 【与 SqlSugar 实体的区别】
|
|
|
// - SqlSugar 实体(如 HwWeb):映射到业务表,用于 CRUD 操作
|
|
|
// - EF Core 实体(如 HwPortalSearchDoc):映射到索引表,用于搜索查询
|
|
|
//
|
|
|
// 为什么搜索用 EF Core 而不是 SqlSugar?
|
|
|
// 1. EF Core 的 LINQ 查询更强大
|
|
|
// 2. EF Core 对复杂查询的支持更好
|
|
|
// 3. 项目技术栈混合使用,各取所长
|
|
|
//
|
|
|
// 【与 Java Spring Boot 的对比】
|
|
|
// Java Spring Data JPA:
|
|
|
// @Entity
|
|
|
// @Table(name = "hw_portal_search_doc")
|
|
|
// @Index(name = "uk_doc_id", columnList = "doc_id", unique = true)
|
|
|
// public class HwPortalSearchDoc { ... }
|
|
|
//
|
|
|
// EF Core:
|
|
|
// [Table("hw_portal_search_doc")]
|
|
|
// [Index(nameof(DocId), IsUnique = true)]
|
|
|
// public class HwPortalSearchDoc { ... }
|
|
|
//
|
|
|
// 两者概念相同,只是注解/特性的写法不同。
|
|
|
// ============================================================================
|
|
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
|
namespace Admin.NET.Plugin.HwPortal;
|
|
|
|
|
|
/// <summary>
|
|
|
/// hw-portal 搜索索引实体。
|
|
|
/// <para>
|
|
|
/// 【设计模式 - CQRS(命令查询职责分离)】
|
|
|
/// 这个实体体现了 CQRS 的"读模型"概念:
|
|
|
/// - 命令模型(HwWeb 等):负责增删改,保证数据一致性
|
|
|
/// - 查询模型(HwPortalSearchDoc):负责查询,优化读取性能
|
|
|
///
|
|
|
/// 好处:
|
|
|
/// 1. 读写分离,各自优化
|
|
|
/// 2. 搜索失败不影响主业务
|
|
|
/// 3. 可以针对搜索场景做特殊处理
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
[Table("hw_portal_search_doc")]
|
|
|
// 【EF Core 索引特性】
|
|
|
// [Index(nameof(DocId), IsUnique = true)] 创建唯一索引。
|
|
|
// nameof(DocId) 获取属性名称字符串,避免硬编码。
|
|
|
//
|
|
|
// 对比 Java JPA:
|
|
|
// Java: @Index(name = "uk_doc_id", columnList = "doc_id", unique = true)
|
|
|
// C#: [Index(nameof(DocId), IsUnique = true)]
|
|
|
//
|
|
|
// C# 的 nameof 更安全,重构时编译器会检查。
|
|
|
[Index(nameof(DocId), IsUnique = true)]
|
|
|
[Index(nameof(SourceType))]
|
|
|
[Index(nameof(UpdatedAt))]
|
|
|
public class HwPortalSearchDoc
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 主键ID。
|
|
|
/// <para>
|
|
|
/// 【C# 语法知识点 - [Key] 特性】
|
|
|
/// [Key] 标记主键字段。
|
|
|
///
|
|
|
/// 对比 Java JPA:
|
|
|
/// Java: @Id
|
|
|
/// @GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
|
/// private Long id;
|
|
|
///
|
|
|
/// EF Core 会自动识别名为 Id 或 {类名}Id 的属性为主键,
|
|
|
/// 但显式标注 [Key] 更清晰。
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
[Key]
|
|
|
public long Id { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 搜索文档唯一键。
|
|
|
/// <para>
|
|
|
/// 【业务说明】
|
|
|
/// DocId 是文档的唯一标识,格式通常是:{SourceType}_{BizId}
|
|
|
/// 例如:hw_web_100, hw_product_200
|
|
|
///
|
|
|
/// 为什么需要 DocId?
|
|
|
/// 1. 全局唯一:不同来源的文档可以区分
|
|
|
/// 2. 幂等更新:相同 DocId 的文档会被更新而不是重复插入
|
|
|
/// </para>
|
|
|
/// <para>
|
|
|
/// 【C# 语法知识点 - [Required] 和 [MaxLength] 特性】
|
|
|
/// [Required]:必填字段,不能为 null
|
|
|
/// [MaxLength(128)]:最大长度 128 字符
|
|
|
///
|
|
|
/// 对比 Java JPA:
|
|
|
/// Java: @Column(name = "doc_id", nullable = false, length = 128)
|
|
|
/// @NotNull
|
|
|
/// private String docId;
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
[Required]
|
|
|
[MaxLength(128)]
|
|
|
public string DocId { get; set; } = string.Empty;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 来源类型(如 hw_web, hw_product 等)。
|
|
|
/// </summary>
|
|
|
[Required]
|
|
|
[MaxLength(32)]
|
|
|
public string SourceType { get; set; } = string.Empty;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 业务主键(如 web_id, product_info_id 等)。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string BizId { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 搜索标题。
|
|
|
/// </summary>
|
|
|
[MaxLength(500)]
|
|
|
public string Title { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 搜索正文内容。
|
|
|
/// <para>
|
|
|
/// 【EF Core 列类型映射】
|
|
|
/// Content 字段在 DbContext.OnModelCreating 中被映射为 longtext:
|
|
|
/// entity.Property(x => x.Content).HasColumnType("longtext");
|
|
|
///
|
|
|
/// 这是因为搜索内容可能很长,需要大文本类型。
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
public string Content { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 页面编码(用于跳转到详情页)。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string WebCode { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 类型ID。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string TypeId { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 设备ID。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string DeviceId { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 菜单ID。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string MenuId { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 文档ID。
|
|
|
/// </summary>
|
|
|
[MaxLength(64)]
|
|
|
public string DocumentId { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 基础分值(用于排序)。
|
|
|
/// </summary>
|
|
|
public int BaseScore { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 前台路由(用户点击搜索结果跳转的页面)。
|
|
|
/// </summary>
|
|
|
[MaxLength(255)]
|
|
|
public string Route { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 前台路由参数(JSON 格式)。
|
|
|
/// <para>
|
|
|
/// 【JSON 列类型】
|
|
|
/// 在 DbContext 中映射为 json 类型:
|
|
|
/// entity.Property(x => x.RouteQueryJson).HasColumnType("json");
|
|
|
///
|
|
|
/// MySQL 5.7+ 支持 JSON 类型,可以直接存储 JSON 数据。
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
public string RouteQueryJson { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 编辑路由(后台编辑页面的路由)。
|
|
|
/// </summary>
|
|
|
[MaxLength(255)]
|
|
|
public string EditRoute { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 逻辑删除标记。
|
|
|
/// <para>
|
|
|
/// 【逻辑删除】
|
|
|
/// "0":正常
|
|
|
/// "1":已删除
|
|
|
///
|
|
|
/// 搜索索引也需要逻辑删除,因为:
|
|
|
/// 1. 删除业务数据时,索引也要标记删除
|
|
|
/// 2. 可以保留历史记录用于审计
|
|
|
/// </para>
|
|
|
/// </summary>
|
|
|
[MaxLength(1)]
|
|
|
public string IsDelete { get; set; } = "0";
|
|
|
|
|
|
/// <summary>
|
|
|
/// 业务更新时间(来源数据的更新时间)。
|
|
|
/// </summary>
|
|
|
public DateTime? UpdatedAt { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 索引创建时间。
|
|
|
/// </summary>
|
|
|
public DateTime CreatedAt { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 索引更新时间。
|
|
|
/// </summary>
|
|
|
public DateTime ModifiedAt { get; set; }
|
|
|
}
|