目录
创建索引
创建索引模板
添加索引对象
添加单个索引对象
批量添加索引对象
更新索引对象
单个更新索引对象
批量更新索引对象
局部更新
删除索引对象
单个删除索引对象
批量删除索引对象
根据Id获取索引对象
单个Id获取索引对象
根据Id批量获取索引对象
普通分页
滚动查询
其它使用到的私有方法
全部代码
NEST是elasticsearch为.net 提供的高级客户端依赖组件。这里为了方便在NET7中使用NEST客户端,我们对NEST的相关方法做了封装,以便在NET7中调用。
搜索我们创建索引的时候,需要先判断索引是否存在,如果存在索引,则返回,不存在,则添加。
GetIndexName()方法是通过实体配置属性来获取索引名称,如下:
private string GetIndexName()
{
var indexName = typeof(TEntity).GetCustomAttribute()?.RelationName ?? string.Empty;
if (indexName.IsBlank())
{
throw new ArgumentNullException($"{nameof(TEntity)}没有配置MetaIndex属性。");
}
return indexName;
}
///
/// 创建索引
///
///
///
public async Task CreateIndexAsync()
{
var indexName = GetIndexName();
var existResponse = await _elasticClient.Indices.ExistsAsync(indexName);
if (existResponse.Exists)
{
return;
}
//创建索引,自动转换类型,order为索引名称
var response = await _elasticClient.Indices.CreateAsync(indexName, c => c.Map(m => m.AutoMap()));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}索引创建失败:{response.DebugInformation}。");
}
}
关于elasticsearch的模板索引的定义,以及使用方法,这里就不做过多的解释,如果需要了解的,请移步:ElasticSearch索引模板 - 简书
///
/// 创建索引模板
///
/// 索引模板编号名称
/// 别名
/// 模板通配符表达式
///
public async Task CreateTemplateAsync(string templateName, string templateAlias, string templatePattern)
{
var existResponse = await _elasticClient.Indices.TemplateV2ExistsAsync(templateName);
if (existResponse.Exists)
{
return;
}
ITemplate selectorTemplate(TemplateDescriptor x) => x.Aliases(a => a.Alias(templateAlias)).Mappings(m => m.AutoMap());
IPutIndexTemplateV2Request selector(PutIndexTemplateV2Descriptor x) => x.IndexPatterns(templatePattern).Template(selectorTemplate);
var templateResponse = await _elasticClient.Indices.PutTemplateV2Async(templateName, selector);
if (!templateResponse.IsValid)
{
throw new BusinessException($"{templateName}索引模板添加失败:{templateResponse.DebugInformation}。");
}
}
///
/// 删除索引模板
///
/// 模板名称编码
///
///
public async Task DeleteTemplateAsync(string templateName)
{
var existResponse = await _elasticClient.Indices.TemplateV2ExistsAsync(templateName);
if (!existResponse.Exists)
{
return;
}
var response = await _elasticClient.Indices.DeleteTemplateV2Async(templateName);
if (!response.IsValid)
{
throw new BusinessException($"{templateName}索引模板删除失败:{response.DebugInformation}。");
}
}
///
/// 单个对象添加
///
/// 数据对象
///
///
public async Task AddAsync(TEntity data)
{
var indexName = GetIndexName();
await AddAsync(indexName, data);
}
///
/// 添加单个对象到指定索引
///
/// 索引名称
/// 数据对象
///
///
public async Task AddAsync(string indexName, TEntity data)
{
var response = await _elasticClient.IndexAsync(data, x => x.Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}添加失败。");
}
}
///
/// 批量添加
///
///
///
///
public async Task AddsAsync(IList datas)
{
var indexName = GetIndexName();
await AddsAsync(indexName, datas);
}
///
/// 批量添加对象集合到指定索引
///
/// 索引名称
///
///
///
public async Task AddsAsync(string indexName, IList datas)
{
if (datas.IsNullOrEmpty())
{
return;
}
//分页推送-防止数据量过大接口超时
int page = 1;
int pageSize = 1000;
int totalPage = (datas.Count + pageSize - 1) / pageSize;
while (page <= totalPage)
{
try
{
//本次推送的数据
var currentPushDatas = datas.Skip((page - 1) * pageSize).Take(pageSize).ToList();
var response = await _elasticClient.BulkAsync(b => b.Index(indexName).IndexMany(currentPushDatas));
if (!response.IsValid)
{
_logger?.LogInformation($"{indexName}批量添加失败:{JsonSerializer.Serialize(response)}");
}
}
catch (Exception ex)
{
//记录日志
_logger?.LogError(ex, $"{indexName}批量添加异常page={page}:{ex}");
}
//下一页
page++;
}
}
public void BulkAll(IList datas)
{
var index = GetIndexName();
BulkAll(index, datas);
}
public void BulkAll(string indexName, IList datas)
{
if (datas.IsNullOrEmpty())
{
return;
}
var bulkAllObserver = _elasticClient.BulkAll(datas, b => b.Index(indexName)
.BackOffTime("30s")//集群繁忙,报429错误码的时候,等待多久进行重试
.BackOffRetries(2) //重试次数
.RefreshOnCompleted() //
.MaxDegreeOfParallelism(Environment.ProcessorCount)
.Size(1000) //每次 bulk 请求时的文档数量。
).Wait(TimeSpan.FromSeconds(30), next =>
{
//执行索引并等待 1min,BulkAll 请求虽然时异步的,但是是一个阻塞操作。
});
}
///
/// 单个更新
///
///
///
///
public async Task UpdateAsync(TEntity data)
{
var indexName = GetIndexName();
await UpdateAsync(indexName, data);
}
///
/// 更新指定索引的对象
///
/// 索引名称
///
///
///
public async Task UpdateAsync(string indexName, TEntity data)
{
DocumentPath documentPath = new(data.Id);
var response = await _elasticClient.UpdateAsync(documentPath, (p) => p.Doc(data).Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}更新失败。");
}
}
///
/// 批量更新
///
///
///
///
public async Task UpdatesAsnyc(IList datas)
{
var indexName = GetIndexName();
await UpdatesAsnyc(indexName, datas);
}
///
/// 批量更新指定索引的对象
///
/// 索引名称
///
///
///
public async Task UpdatesAsnyc(string indexName, IList datas)
{
var updateDescriptor = new BulkDescriptor();
foreach (var data in datas)
{
updateDescriptor.Update(i => i
.Index(indexName)
.Id(data.Id)
.Doc(data)
.DocAsUpsert(true));
}
var response = await _elasticClient.BulkAsync(updateDescriptor);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量更新失败。");
}
}
///
/// 批量局部更新
///
///
///
///
///
public async Task UpdatesPartitialAsnyc(IList datas, Expression> express)
{
var indexName = GetIndexName();
await UpdatesPartitialAsnyc(indexName, datas, express);
}
///
/// 批量局部更新指定索引
///
/// 索引名称
///
///
///
///
public async Task UpdatesPartitialAsnyc(string indexName, IList datas, Expression> express)
{
var updateDescriptor = new BulkDescriptor();
var columns = Metas(express);
foreach (var data in datas)
{
var updateData = ToPaititailUpdateData(data, columns);
updateDescriptor.Update>(i => i
.Index(indexName)
.Id(data.Id)
.Doc(updateData)
.DocAsUpsert(true));
}
var response = await _elasticClient.BulkAsync(updateDescriptor);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量局部更新失败。");
}
}
///
/// 批量局部更新
///
///
///
///
///
public async Task UpdatesPartitialAsnyc(IList datas, Expression> express)
{
var indexName = GetIndexName();
await UpdatesPartitialAsnyc(indexName, datas, express);
}
///
/// 批量局部更新指定索引
///
/// 索引名称
///
///
///
///
public async Task UpdatesPartitialAsnyc(string indexName, IList datas, Expression> express)
{
var updateDescriptor = new BulkDescriptor();
var columns = Metas(express);
foreach (var data in datas)
{
var updateData = ToPaititailUpdateData(data, columns);
updateDescriptor.Update>(i => i
.Index(indexName)
.Id(data.Id)
.Doc(updateData)
.DocAsUpsert(true));
}
var response = await _elasticClient.BulkAsync(updateDescriptor);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量局部更新失败。");
}
}
///
/// 单个删除
///
///
///
///
public async Task DeleteAsync(string id)
{
var indexName = GetIndexName();
await DeleteAsync(indexName, id);
}
///
/// 单个删除
///
/// 索引名称
/// 数据id
///
///
public async Task DeleteAsync(string indexName, string id)
{
if (string.IsNullOrWhiteSpace(id))
{
return;
}
var response = await _elasticClient.DeleteAsync(id, i => i.Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}删除失败。");
}
}
///
/// 批量删除
///
///
///
///
public async Task DeletesAsync(IList ids)
{
var indexName = GetIndexName();
await DeletesAsync(indexName, ids);
}
///
/// 批量删除
///
/// 索引名称
///
///
///
public async Task DeletesAsync(string indexName, IList ids)
{
if (ids.IsNullOrEmpty())
{
return;
}
var bulkQuest = new BulkRequest()
{
Operations = new List()
};
foreach (var id in ids)
{
bulkQuest.Operations.Add(new BulkDeleteOperation(id));
}
var response = await _elasticClient.BulkAsync(bulkQuest);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量删除失败。");
}
}
///
/// 根据Id获取对象
///
///
///
public async Task GetByIdAsync(string id)
{
var indexName = GetIndexName();
return await GetByIdAsync(indexName, id);
}
///
/// 根据Id获取对象
///
/// 索引名称
///
///
public async Task GetByIdAsync(string indexName, string id)
{
if (string.IsNullOrWhiteSpace(id))
{
return null;
}
var response = await _elasticClient.GetAsync(id, x => x.Index(indexName));
return response.Source;
}
///
/// 根据Id集合批量获取数据集合
///
///
///
public async Task> GetByIdsAsync(IList ids)
{
var indexName = GetIndexName();
return await GetByIdsAsync(indexName, ids);
}
///
/// 根据Id集合批量获取数据集合
///
/// 索引名称
///
///
public async Task> GetByIdsAsync(string indexName, IList ids)
{
if (ids.IsNullOrEmpty())
{
return new List();
}
var response = await _elasticClient.SearchAsync(x => x.Query(o => o.Ids(m => m.Values(ids))).Index(indexName));
return response.Documents.ToList();
}
///
/// 普通分页搜索
///
///
///
public async Task> SearchPageAsync(BaseCondition condition)
{
var indexName = GetIndexName();
return await SearchPageAsync(indexName, condition);
}
///
/// 普通分页搜索
///
/// 索引名称
///
///
public async Task> SearchPageAsync(string indexName, BaseCondition condition)
{
var query = new QueryContainerDescriptor();
foreach (var data in condition.SearchFields)
{
query.Term(data.Key, data.Value);
}
ISearchRequest searchSelector(SearchDescriptor s) => s.Index(indexName)
.Query(x => query)
.From((condition.Page - 1) * condition.PageSize)
.Size(condition.PageSize);
var response = await _elasticClient.SearchAsync(searchSelector);
ICountRequest countQuery(CountDescriptor s) => s.Index(indexName)
.Query(x => query);
var countResponse = await _elasticClient.CountAsync(countQuery);
return new PagedResult
{
Page = condition.Page,
PageSize = condition.PageSize,
Total = countResponse.Count,
Rows = response.Documents.ToList()
};
}
///
/// 滚动查询
///
///
///
public async Task> ScrollSearchAsync(BaseCondition condition)
{
var indexName = GetIndexName();
return await ScrollSearchAsync(indexName, condition);
}
///
/// 滚动查询
///
/// 索引名称
///
///
public async Task> ScrollSearchAsync(string indexName, BaseCondition condition)
{
var query = new QueryContainerDescriptor();
foreach (var data in condition.SearchFields)
{
query.Term(data.Key, data.Value);
}
ISearchRequest searchSelector(SearchDescriptor s) => s.Index(indexName)
.Query(x => query)
.Size(condition.PageSize)
.Scroll(Time.MinusOne);
var response = await _elasticClient.SearchAsync(searchSelector);
var returnDatas = new List();
returnDatas.AddRange(response.Documents);
string scrollId = response.ScrollId;
while (true)
{
var scrollResponse = await _elasticClient.ScrollAsync("1m", scrollId);
if (scrollResponse.Documents.IsNullOrEmpty())
{
break;
}
returnDatas.AddRange(scrollResponse.Documents);
}
return returnDatas;
}
///
/// 获取MetaName
///
///
///
///
///
///
private string[] Metas(Expression> express)
{
if (express == null)
{
throw new ArgumentNullException(nameof(express));
}
if (express.Body.NodeType == ExpressionType.MemberAccess)
{
return new[] { (express.Body as MemberExpression).Member.GetMetaName() };
}
if (express.Body.NodeType == ExpressionType.New)
{
NewExpression newExpression = express.Body as NewExpression;
if (newExpression == null || newExpression.Arguments.Count == 0)
{
throw new ArgumentException($"请为类型 {typeof(TEntity).FullName} 的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
string[] array = new string[newExpression.Arguments.Count];
for (int i = 0; i < array.Length; i++)
{
array[i] = (newExpression.Arguments[i] as MemberExpression).Member.GetMetaName();
}
return array;
}
if (express.Body.NodeType == ExpressionType.Convert)
{
MemberExpression memberExpression2;
if ((memberExpression2 = (express.Body as UnaryExpression)?.Operand as MemberExpression) == null)
{
throw new ArgumentException($"请为类型 {typeof(TEntity).FullName} 的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
return new[] { memberExpression2.Member.GetMetaName() };
}
throw new ArgumentException($"请为类型{typeof(TEntity).FullName}的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
///
/// 转换成局部更新对象
///
///
///
///
private Dictionary ToPaititailUpdateData(TEntity entity, string[] updateColumns)
{
var properties = entity.GetType().GetProperties();
var updateDatas = new Dictionary();
foreach (var property in properties)
{
if (updateColumns.Any(col => col.ToLower() == property.Name.ToLower()))
{
var newName = property.Name.ToLowerCamel();
updateDatas[newName] = property.GetValue(entity);
}
}
return updateDatas;
}
using JuCheap.Core.Exceptions;
using JuCheap.Core.Extentions;
using JuCheap.Entity;
using Microsoft.Extensions.Logging;
using Nest;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Cryptography;
using System.Text.Json;
namespace JuCheap.Core.Elasticsearch
{
public class ElasticsearchBaseProvider where TEntity : class, IBaseEntity, new()
{
private readonly IElasticClient _elasticClient;
private readonly ILogger> _logger;
public ElasticsearchBaseProvider(IElasticClient elasticClient
, ILogger> logger)
{
_elasticClient = elasticClient;
_logger = logger;
}
private string GetIndexName()
{
var indexName = typeof(TEntity).GetCustomAttribute()?.RelationName ?? string.Empty;
if (indexName.IsBlank())
{
throw new ArgumentNullException($"{nameof(TEntity)}没有配置MetaIndex属性。");
}
return indexName;
}
///
/// 创建索引
///
///
///
public async Task CreateIndexAsync()
{
var indexName = GetIndexName();
var existResponse = await _elasticClient.Indices.ExistsAsync(indexName);
if (existResponse.Exists)
{
return;
}
//创建索引,自动转换类型,order为索引名称
var response = await _elasticClient.Indices.CreateAsync(indexName, c => c.Map(m => m.AutoMap()));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}索引创建失败:{response.DebugInformation}。");
}
}
///
/// 创建索引模板
///
/// 索引模板编号名称
/// 别名
/// 模板通配符表达式
///
public async Task CreateTemplateAsync(string templateName, string templateAlias, string templatePattern)
{
var existResponse = await _elasticClient.Indices.TemplateV2ExistsAsync(templateName);
if (existResponse.Exists)
{
return;
}
ITemplate selectorTemplate(TemplateDescriptor x) => x.Aliases(a => a.Alias(templateAlias)).Mappings(m => m.AutoMap());
IPutIndexTemplateV2Request selector(PutIndexTemplateV2Descriptor x) => x.IndexPatterns(templatePattern).Template(selectorTemplate);
var templateResponse = await _elasticClient.Indices.PutTemplateV2Async(templateName, selector);
if (!templateResponse.IsValid)
{
throw new BusinessException($"{templateName}索引模板添加失败:{templateResponse.DebugInformation}。");
}
}
///
/// 删除索引模板
///
/// 模板名称编码
///
///
public async Task DeleteTemplateAsync(string templateName)
{
var existResponse = await _elasticClient.Indices.TemplateV2ExistsAsync(templateName);
if (!existResponse.Exists)
{
return;
}
var response = await _elasticClient.Indices.DeleteTemplateV2Async(templateName);
if (!response.IsValid)
{
throw new BusinessException($"{templateName}索引模板删除失败:{response.DebugInformation}。");
}
}
///
/// 单个对象添加
///
/// 数据对象
///
///
public async Task AddAsync(TEntity data)
{
var indexName = GetIndexName();
await AddAsync(indexName, data);
}
///
/// 添加单个对象到指定索引
///
/// 索引名称
/// 数据对象
///
///
public async Task AddAsync(string indexName, TEntity data)
{
var response = await _elasticClient.IndexAsync(data, x => x.Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}添加失败。");
}
}
///
/// 批量添加
///
///
///
///
public async Task AddsAsync(IList datas)
{
var indexName = GetIndexName();
await AddsAsync(indexName, datas);
}
///
/// 批量添加对象集合到指定索引
///
/// 索引名称
///
///
///
public async Task AddsAsync(string indexName, IList datas)
{
if (datas.IsNullOrEmpty())
{
return;
}
//分页推送-防止数据量过大接口超时
int page = 1;
int pageSize = 1000;
int totalPage = (datas.Count + pageSize - 1) / pageSize;
while (page <= totalPage)
{
try
{
//本次推送的数据
var currentPushDatas = datas.Skip((page - 1) * pageSize).Take(pageSize).ToList();
var response = await _elasticClient.BulkAsync(b => b.Index(indexName).IndexMany(currentPushDatas));
if (!response.IsValid)
{
_logger?.LogInformation($"{indexName}批量添加失败:{JsonSerializer.Serialize(response)}");
}
}
catch (Exception ex)
{
//记录日志
_logger?.LogError(ex, $"{indexName}批量添加异常page={page}:{ex}");
}
//下一页
page++;
}
}
public void BulkAll(IList datas)
{
var index = GetIndexName();
BulkAll(index, datas);
}
public void BulkAll(string indexName, IList datas)
{
if (datas.IsNullOrEmpty())
{
return;
}
var bulkAllObserver = _elasticClient.BulkAll(datas, b => b.Index(indexName)
.BackOffTime("30s")//集群繁忙,报429错误码的时候,等待多久进行重试
.BackOffRetries(2) //重试次数
.RefreshOnCompleted() //
.MaxDegreeOfParallelism(Environment.ProcessorCount)
.Size(1000) //每次 bulk 请求时的文档数量。
).Wait(TimeSpan.FromSeconds(30), next =>
{
//执行索引并等待 1min,BulkAll 请求虽然时异步的,但是是一个阻塞操作。
});
}
///
/// 单个更新
///
///
///
///
public async Task UpdateAsync(TEntity data)
{
var indexName = GetIndexName();
await UpdateAsync(indexName, data);
}
///
/// 更新指定索引的对象
///
/// 索引名称
///
///
///
public async Task UpdateAsync(string indexName, TEntity data)
{
DocumentPath documentPath = new(data.Id);
var response = await _elasticClient.UpdateAsync(documentPath, (p) => p.Doc(data).Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}更新失败。");
}
}
///
/// 批量更新
///
///
///
///
public async Task UpdatesAsnyc(IList datas)
{
var indexName = GetIndexName();
await UpdatesAsnyc(indexName, datas);
}
///
/// 批量更新指定索引的对象
///
/// 索引名称
///
///
///
public async Task UpdatesAsnyc(string indexName, IList datas)
{
var updateDescriptor = new BulkDescriptor();
foreach (var data in datas)
{
updateDescriptor.Update(i => i
.Index(indexName)
.Id(data.Id)
.Doc(data)
.DocAsUpsert(true));
}
var response = await _elasticClient.BulkAsync(updateDescriptor);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量更新失败。");
}
}
///
/// 批量局部更新
///
///
///
///
///
public async Task UpdatesPartitialAsnyc(IList datas, Expression> express)
{
var indexName = GetIndexName();
await UpdatesPartitialAsnyc(indexName, datas, express);
}
///
/// 批量局部更新指定索引
///
/// 索引名称
///
///
///
///
public async Task UpdatesPartitialAsnyc(string indexName, IList datas, Expression> express)
{
var updateDescriptor = new BulkDescriptor();
var columns = Metas(express);
foreach (var data in datas)
{
var updateData = ToPaititailUpdateData(data, columns);
updateDescriptor.Update>(i => i
.Index(indexName)
.Id(data.Id)
.Doc(updateData)
.DocAsUpsert(true));
}
var response = await _elasticClient.BulkAsync(updateDescriptor);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量局部更新失败。");
}
}
///
/// 单个删除
///
///
///
///
public async Task DeleteAsync(string id)
{
var indexName = GetIndexName();
await DeleteAsync(indexName, id);
}
///
/// 单个删除
///
/// 索引名称
/// 数据id
///
///
public async Task DeleteAsync(string indexName, string id)
{
if (string.IsNullOrWhiteSpace(id))
{
return;
}
var response = await _elasticClient.DeleteAsync(id, i => i.Index(indexName));
if (!response.IsValid)
{
throw new BusinessException($"{indexName}删除失败。");
}
}
///
/// 批量删除
///
///
///
///
public async Task DeletesAsync(IList ids)
{
var indexName = GetIndexName();
await DeletesAsync(indexName, ids);
}
///
/// 批量删除
///
/// 索引名称
///
///
///
public async Task DeletesAsync(string indexName, IList ids)
{
if (ids.IsNullOrEmpty())
{
return;
}
var bulkQuest = new BulkRequest()
{
Operations = new List()
};
foreach (var id in ids)
{
bulkQuest.Operations.Add(new BulkDeleteOperation(id));
}
var response = await _elasticClient.BulkAsync(bulkQuest);
if (!response.IsValid)
{
throw new BusinessException($"{indexName}批量删除失败。");
}
}
///
/// 根据Id获取对象
///
///
///
public async Task GetByIdAsync(string id)
{
var indexName = GetIndexName();
return await GetByIdAsync(indexName, id);
}
///
/// 根据Id获取对象
///
/// 索引名称
///
///
public async Task GetByIdAsync(string indexName, string id)
{
if (string.IsNullOrWhiteSpace(id))
{
return null;
}
var response = await _elasticClient.GetAsync(id, x => x.Index(indexName));
return response.Source;
}
///
/// 根据Id集合批量获取数据集合
///
///
///
public async Task> GetByIdsAsync(IList ids)
{
var indexName = GetIndexName();
return await GetByIdsAsync(indexName, ids);
}
///
/// 根据Id集合批量获取数据集合
///
/// 索引名称
///
///
public async Task> GetByIdsAsync(string indexName, IList ids)
{
if (ids.IsNullOrEmpty())
{
return new List();
}
var response = await _elasticClient.SearchAsync(x => x.Query(o => o.Ids(m => m.Values(ids))).Index(indexName));
return response.Documents.ToList();
}
///
/// 普通分页搜索
///
///
///
public async Task> SearchPageAsync(BaseCondition condition)
{
var indexName = GetIndexName();
return await SearchPageAsync(indexName, condition);
}
///
/// 普通分页搜索
///
/// 索引名称
///
///
public async Task> SearchPageAsync(string indexName, BaseCondition condition)
{
var query = new QueryContainerDescriptor();
foreach (var data in condition.SearchFields)
{
query.Term(data.Key, data.Value);
}
ISearchRequest searchSelector(SearchDescriptor s) => s.Index(indexName)
.Query(x => query)
.From((condition.Page - 1) * condition.PageSize)
.Size(condition.PageSize);
var response = await _elasticClient.SearchAsync(searchSelector);
ICountRequest countQuery(CountDescriptor s) => s.Index(indexName)
.Query(x => query);
var countResponse = await _elasticClient.CountAsync(countQuery);
return new PagedResult
{
Page = condition.Page,
PageSize = condition.PageSize,
Total = countResponse.Count,
Rows = response.Documents.ToList()
};
}
///
/// 滚动查询
///
///
///
public async Task> ScrollSearchAsync(BaseCondition condition)
{
var indexName = GetIndexName();
return await ScrollSearchAsync(indexName, condition);
}
///
/// 滚动查询
///
/// 索引名称
///
///
public async Task> ScrollSearchAsync(string indexName, BaseCondition condition)
{
var query = new QueryContainerDescriptor();
foreach (var data in condition.SearchFields)
{
query.Term(data.Key, data.Value);
}
ISearchRequest searchSelector(SearchDescriptor s) => s.Index(indexName)
.Query(x => query)
.Size(condition.PageSize)
.Scroll(Time.MinusOne);
var response = await _elasticClient.SearchAsync(searchSelector);
var returnDatas = new List();
returnDatas.AddRange(response.Documents);
string scrollId = response.ScrollId;
while (true)
{
var scrollResponse = await _elasticClient.ScrollAsync("1m", scrollId);
if (scrollResponse.Documents.IsNullOrEmpty())
{
break;
}
returnDatas.AddRange(scrollResponse.Documents);
}
return returnDatas;
}
///
/// 获取MetaName
///
///
///
///
///
///
private string[] Metas(Expression> express)
{
if (express == null)
{
throw new ArgumentNullException(nameof(express));
}
if (express.Body.NodeType == ExpressionType.MemberAccess)
{
return new[] { (express.Body as MemberExpression).Member.GetMetaName() };
}
if (express.Body.NodeType == ExpressionType.New)
{
NewExpression newExpression = express.Body as NewExpression;
if (newExpression == null || newExpression.Arguments.Count == 0)
{
throw new ArgumentException($"请为类型 {typeof(TEntity).FullName} 的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
string[] array = new string[newExpression.Arguments.Count];
for (int i = 0; i < array.Length; i++)
{
array[i] = (newExpression.Arguments[i] as MemberExpression).Member.GetMetaName();
}
return array;
}
if (express.Body.NodeType == ExpressionType.Convert)
{
MemberExpression memberExpression2;
if ((memberExpression2 = (express.Body as UnaryExpression)?.Operand as MemberExpression) == null)
{
throw new ArgumentException($"请为类型 {typeof(TEntity).FullName} 的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
return new[] { memberExpression2.Member.GetMetaName() };
}
throw new ArgumentException($"请为类型{typeof(TEntity).FullName}的指定一个字段(Field)或属性(Property)的集合作为 Lambda 的主体(Body)。");
}
///
/// 转换成局部更新对象
///
///
///
///
private Dictionary ToPaititailUpdateData(TEntity entity, string[] updateColumns)
{
var properties = entity.GetType().GetProperties();
var updateDatas = new Dictionary();
foreach (var property in properties)
{
if (updateColumns.Any(col => col.ToLower() == property.Name.ToLower()))
{
var newName = property.Name.ToLowerCamel();
updateDatas[newName] = property.GetValue(entity);
}
}
return updateDatas;
}
}
}
BaseCondition.cs
using JuCheap.Core.Exceptions;
using System.Text.Json.Serialization;
namespace JuCheap.Core
{
///
/// 分页查询条件基础类
///
public class BaseCondition
{
public BaseCondition()
{
SearchFields = new Dictionary();
}
///
/// 升序排列常量
///
public const string Asc = "ascending";
///
/// 降序排列常量
///
public const string Desc = "descending";
///
/// 当前页码
///
public int Page { get; set; }
///
/// 每页显示的数据条数
///
public int PageSize { get; set; }
///
/// 排序字段
///
[JsonPropertyName("prop")]
public string? SortField { get; set; }
///
/// 排序方式
///
[JsonPropertyName("order")]
public string? SortType { get; set; }
///
/// 公司Id
///
public string? CompanyId { get; set; }
///
/// 搜索关键字
///
public string? Keyword { get; set; }
///
/// 高级搜索条件
///
public IDictionary SearchFields { get; set; }
///
/// 转换成数据库排序规则
///
///
public virtual string ToSort()
{
string direction = SortType == Asc ? "asc" : "desc";
return $" {SortField} {direction} ";
}
///
/// 自定义参数校验
///
protected virtual void CustomValidate() { }
///
/// 参数校验
///
/// 校验不通过抛出BusinessException异常
public void Validate()
{
if (Page <= 0)
throw new BusinessException("当前页码必须大于0 !");
if (PageSize < 1)
throw new BusinessException("每页显示条数必须大于0 !");
if (PageSize > 1000)
throw new BusinessException("每页显示数据最大条数不能超过1千条");
CustomValidate();
}
}
///
/// 搜索条件模型
///
public class ConditionItem
{
public ConditionItem() { }
public ConditionItem(string value)
{
Value = value;
}
///
/// 搜索值
///
public string Value { get; set; }
///
/// 匹配类型(比如:like,eq,gt,gte,lt,lte等)
///
public string Type { get; set; }
///
/// 支持区间查询
///
public string EndValue { get; set; }
///
/// 控件类型
///
public byte? ControlType { get; set; }
///
/// 显示名称
///
public string DisplayName { get; set; }
}
}