在上一篇文章中,简单的做了一个测试,对已有项目进行改造。测试完发现,对于已有数据只能采用全部重建索引的方式。如果是初始化的项目,可以在创建、更新数据库实体的同时同步创建、更新索引,这样既能确保数据库实体与索引的同步,也能将创建索引的时间平均分配至每次单元操作中。在业务流程上也要尽量避免频繁的重建全部索引。所以,在本篇文章中将解决这个问题:
怎么实现索引的同步呢?这里,我们不可能将代码写到每个接口方法中,这样,代码太冗余了。既然是对实体的操作,能不能在上下文SaveChange之前或者之后做一些事情呢?这里我将对AuditLogDbContext加一些代码,注意AuditLogDbContext是继承AbpDbContext,只需要重写SaveChanges()或者SaveChangesAsync(),在里面加上索引同步的代码即可。
/// <summary>
/// 用于数据库实体,加上此标识,表示该实体需要进行全文检索
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false)]
public class SearchEntityAttribute : Attribute
{
/// <summary>
/// 是否启用全文检索
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 构造函数
/// </summary>
public SearchEntityAttribute()
{
IsEnabled = true;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="isEnabled"></param>
public SearchEntityAttribute(bool isEnabled)
{
IsEnabled = isEnabled;
}
}
保存数据前的操作,判断实体跟踪的状态,如果是增删改的状态,则判断该实体有没有标记SearchEntityAttribute 特性,如果有,则记录该实体的数据。
/// <summary>
/// 保存数据前操作
/// </summary>
/// <returns></returns>
protected Task BeforeSaveChanges()
{
if (AuditConfig.AuditConfigOptions.AuditEnabled)// && AuditConfig.AuditConfigOptions.Stores.Count > 0
{
foreach (var entityEntry in ChangeTracker.Entries())
{
if (entityEntry.State == EntityState.Detached || entityEntry.State == EntityState.Unchanged)
{
continue;
}
//
if (AuditConfig.AuditConfigOptions.EntityFilters.Any(entityFilter =>
entityFilter.Invoke(entityEntry) == false))
{
continue;
}
//判断实体中有LogEntity特性,如果有且IsEnabled==true就记录日志
var attribuate= entityEntry.Entity.GetType().GetCustomAttribute<LogEntityAttribute>();
if (attribuate != null&& attribuate.IsEnabled)
{
AuditEntries.Add(new InternalAuditEntry(entityEntry));
}
//判断实体中有SearchEntity特性,如果有且IsEnabled==true就创建索引
var attribuate2 = entityEntry.Entity.GetType().GetCustomAttribute<SearchEntityAttribute>();
if (attribuate2 != null && attribuate2.IsEnabled)
{
SearchEntries.Add(new InternalAuditEntry(entityEntry));
}
}
}
return Task.CompletedTask;
}
保存数据后操作,将BeforeSaveChanges 保存的数据,同步到索引文件中。
/// <summary>
/// 保存数据后操作
/// </summary>
/// <returns></returns>
protected Task AfterSaveChanges()
{
//记录实体变更日志
this.WriteToLog();
//创建(追加)或修改实体索引
this.WriteToLucene();
return Task.CompletedTask;
}
具体来看一下WriteToLucene()方法:
/// <summary>
/// 创建(追加)或修改实体索引
/// </summary>
private void WriteToLucene()
{
if (null != SearchEntries && SearchEntries.Count > 0)
{
foreach (var entry in SearchEntries)
{
if (entry is InternalAuditEntry searchEntry)
{
switch (searchEntry.OperationType)
{
case DataOperationType.Add:
//这里默认:如果不存在索引,则创建新索引,否则将打开索引并追加文档
_searchManager.CreateIndexByEntity(entry.Entities);
break;
case DataOperationType.Delete:
var type_d = entry.Entities.GetType();
//获取entityId
var entityId_d = type_d.GetProperty("Id").GetValue(entry.Entities).ToString();
_searchManager.DeleteIndex(entityId_d);
break;
case DataOperationType.Update:
var type_u = entry.Entities.GetType();
//获取entityId
var entityId_u = type_u.GetProperty("Id").GetValue(entry.Entities).ToString();
var deleted_n = type_u.GetProperty("IsDeleted").GetValue(entry.Entities).ToString();
bool.TryParse(deleted_n, out bool isDeleted);
//如果是软删除,IsDeleted=1
if (isDeleted)
{
_searchManager.DeleteIndex(entityId_u);
}
//如果是修改
else
{
//这里默认:如果不存在索引,则创建新索引,否则将打开索引并追加文档
_searchManager.CreateIndexByEntity(entry.Entities);
}
break;
}
}
}
}
}
/// <summary>
/// 重写SaveChanges
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
BeforeSaveChanges().ConfigureAwait(false).GetAwaiter().GetResult();
var result = base.SaveChanges();
if (result>0)
{
AfterSaveChanges().ConfigureAwait(false).GetAwaiter().GetResult();
}
return result;
}
到此, 改造 AuditLogDbContext的工作就已经完成了……
在实际的代码怎么去应用呢?
首先安装nuget包:RunGo.Security最新版,然后找到项目的实体层RunGo.xxx.EntityFrameworkCore中的xxxDbContext,继承自AuditLogDbContext,最后在需要同步索引的实体类上加上 SearchEntityAttribute 特性。
public class PersonnelDbContext : AuditLogDbContext
{
//todo……
}
[SearchEntity]
public class Archive : FullAuditedEntity<string>, IMayBeHaveTenant, IEntity<string>
{
//todo……
}
| 修改日期 | 修改人 | 备注 |
| 2022-01-27 17:16:01[当前版本] | 俞鹏 | V1.0 |
| 2022-01-27 17:14:16 | 俞鹏 | V1.0 |
| 2022-01-27 17:06:24 | 俞鹏 | V1.0 |
| 2022-01-27 17:05:41 | 俞鹏 | V1.0 |