/// <summary> /// 尝试获取指定表达式的缓存。 /// </summary> /// <param name="expression"></param> /// <param name="func">当缓存不存在时,创建缓存数据的函数。</param> /// <returns></returns> internal static Delegate TryGetDelegate(Expression expression, Func <LambdaExpression> func) { var section = ConfigurationUnity.GetSection <TranslatorConfigurationSection>(); var option = section == null ? TranslateOptions.Default : section.Options; var result = CacheableChecker.Check(expression); if (!result.Required || (result.Enabled == null && !option.CacheParsing) || result.Enabled == false) { return(func().Compile()); } var cacheKey = ExpressionKeyGenerator.GetKey(expression, "Trans"); cacheKey = NativeCacheKeyContext.GetKey(cacheKey); return(MemoryCacheManager.Instance.TryGet(cacheKey, () => { var lambdaExp = func() as LambdaExpression; var segment = SegmentFinder.Find(expression); if (segment != null) { //将表达式内的 Segment 替换成参数 var segParExp = Expression.Parameter(typeof(IDataSegment), "g"); var newExp = SegmentReplacer.Repalce(lambdaExp.Body, segParExp); var parameters = new List <ParameterExpression>(lambdaExp.Parameters); parameters.Insert(1, segParExp); lambdaExp = Expression.Lambda(newExp, parameters.ToArray()); } return lambdaExp.Compile(); }, () => new RelativeTime(result.Expired ?? TimeSpan.FromSeconds(option.CacheParsingTimes)))); }
/// <summary> /// 将查询转换为带分页信息的结构输出。查询中需要使用 Segment 扩展方法带入 <see cref="IPager"/> 分页对象。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source"></param> /// <returns></returns> public static PaginalResult <T> ToPaginalResult <T>(this IQueryable <T> source) { var segment = SegmentFinder.Find(source.Expression); var list = source.ToList(); return(new PaginalResult <T>(list, segment as IPager)); }
/// <summary> /// 查找表达式中的 <see cref="IDataSegment"/> 对象。 /// </summary> /// <param name="expression"></param> /// <returns></returns> public static IDataSegment Find(Expression expression) { var replaer = new SegmentFinder(); replaer.Visit(expression); return(replaer.dataSegment); }
/// <summary> /// 尝试通过表达式获取执行后的结果缓存。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="expression"></param> /// <param name="func"></param> /// <returns></returns> internal static T TryGet <T>(Expression expression, Func <T> func) { var section = ConfigurationUnity.GetSection <TranslatorConfigurationSection>(); var option = section == null ? TranslateOptions.Default : section.Options; var result = CacheableChecker.Check(expression); //没有开启数据缓存 if ((result.Enabled == null && !option.CacheExecution) || result.Enabled == false) { return(func()); } var cacheMgr = CacheManagerFactory.CreateManager(); if (cacheMgr == null) { return(func()); } var cacheKey = ExpressionKeyGenerator.GetKey(expression, "Exec"); cacheKey = NativeCacheKeyContext.GetKey(cacheKey); Reference(cacheKey, expression); var segment = SegmentFinder.Find(expression); var pager = segment as DataPager; var cacheFunc = new Func <CacheItem <T> >(() => { var data = EnumerateData(func()); var isEnumerable = typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(IEnumerable <>); if (isEnumerable) { var elementType = typeof(T).GetEnumerableElementType(); var method = typeof(Enumerable).GetMethod(nameof(Enumerable.ToList)).MakeGenericMethod(elementType); data = (T)method.Invoke(null, new object[] { data }); } var total = 0; if (pager != null) { total = pager.RecordCount; } return(new CacheItem <T> { Data = data, Total = total }); }); var cacheItem = cacheMgr.TryGet(cacheKey, cacheFunc, () => new RelativeTime(result.Expired ?? TimeSpan.FromSeconds(option.CacheExecutionTimes))); if (pager != null) { pager.RecordCount = cacheItem.Total; } return(cacheItem.Data); }
/// <summary> /// 执行 <see cref="Expression"/> 的查询,返回查询结果。 /// </summary> /// <param name="expression">表示 LINQ 查询的表达式树。</param> /// <returns>单值对象。</returns> /// <exception cref="TranslateException">对 LINQ 表达式解析失败时抛出此异常。</exception> public object Execute(Expression expression) { var efn = TranslateCache.TryGetDelegate(expression, () => (LambdaExpression)GetExecutionPlan(expression)); if (efn.Method.GetParameters().Length == 2) { return(efn.DynamicInvoke(service.Database)); } var segment = SegmentFinder.Find(expression); return(efn.DynamicInvoke(service.Database, segment)); }
/// <summary> /// 执行 <see cref="Expression"/> 的查询,返回查询结果。 /// </summary> /// <param name="expression">表示 LINQ 查询的表达式树。</param> /// <returns>单值对象。</returns> /// <exception cref="TranslateException">对 LINQ 表达式解析失败时抛出此异常。</exception> public object Execute(Expression expression) { var efn = TranslateCache.TryGetDelegate(expression, () => (LambdaExpression)GetExecutionPlan(expression)); var attrs = GetMethodAttributes(efn.Method); if (!attrs.Item2) { return(efn.DynamicInvoke(service.Database)); } var segment = SegmentFinder.Find(expression); return(efn.DynamicInvoke(service.Database, segment)); }
/// <summary> /// 尝试通过表达式获取执行后的结果缓存。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="expression"></param> /// <param name="func"></param> /// <returns></returns> internal static T TryGet <T>(Expression expression, Func <T> func) { var section = ConfigurationUnity.GetSection <TranslatorConfigurationSection>(); var option = section == null ? TranslateOptions.Default : section.Options; //没有开启数据缓存 if (!option.DataCacheEnabled) { return(func()); } var cacheMgr = CacheManagerFactory.CreateManager(); if (cacheMgr == null) { return(func()); } var cacheKey = ExpressionKeyGenerator.GetKey(expression, "Exec"); Reference(cacheKey, expression); var segment = SegmentFinder.Find(expression); var pager = segment as DataPager; var cacheFunc = new Func <CacheItem <T> >(() => { var data = func(); var total = 0; if (pager != null) { total = pager.RecordCount; } return(new CacheItem <T> { Data = data, Total = total }); }); var cacheItem = cacheMgr.TryGet(cacheKey, cacheFunc, () => new RelativeTime(TimeSpan.FromSeconds(option.DataCacheExpired))); if (pager != null) { pager.RecordCount = cacheItem.Total; } return(cacheItem.Data); }
/// <summary> /// 执行 <see cref="Expression"/> 的查询,返回查询结果。 /// </summary> /// <param name="expression">表示 LINQ 查询的表达式树。</param> /// <returns>单值对象。</returns> /// <exception cref="TranslateException">对 LINQ 表达式解析失败时抛出此异常。</exception> public async Task <TResult> ExecuteAsync <TResult>(Expression expression, CancellationToken cancellationToken = default) { var efn = TranslateCache.TryGetDelegate(expression, () => (LambdaExpression)GetExecutionPlan(expression)); var attrs = GetMethodAttributes(efn.Method); object result; if (attrs.Item1) { if (attrs.Item2) { var segment = SegmentFinder.Find(expression); result = efn.DynamicInvoke(service.Database, segment, cancellationToken); } else { result = efn.DynamicInvoke(service.Database, cancellationToken); } } else { if (attrs.Item2) { var segment = SegmentFinder.Find(expression); result = efn.DynamicInvoke(service.Database, segment); } else { result = efn.DynamicInvoke(service.Database); } } if (result is TResult) { return((TResult)result); } else if (result is Task <TResult> task) { return(task.Result); } return(default);
/// <summary> /// 尝试获取指定表达式的缓存。 /// </summary> /// <param name="expression"></param> /// <param name="func">当缓存不存在时,创建缓存数据的函数。</param> /// <returns></returns> internal static Expression <Func <IDatabase, object> > TryGet(Expression expression, Func <Expression <Func <IDatabase, object> > > func) { if (!CachaebleChecker.Check(expression)) { return(func()); } var section = ConfigurationUnity.GetSection <TranslatorConfigurationSection>(); var option = section == null ? TranslateOptions.Default : section.Options; if (!option.ParseCacheEnabled) { return(func()); } ClearExpiredKeys(); var lazy = new Lazy <CacheItem>(() => new CacheItem { Expression = func(), Expired = DateTime.Now.AddSeconds(option.ParseCacheExpired) }); var cacheKey = GetKey(expression); var result = cache.GetOrAdd(cacheKey, k => lazy.Value); //在现有的表达式中查找 IDataSegment,去替换缓存中的 IDataSegment //原因是前端需要获得分页信息,如果不进行替换,将无法返回信息 var segment = SegmentFinder.Find(expression); if (segment != null) { result.Expression = (Expression <Func <IDatabase, object> >)SegmentReplacer.Repalce(result.Expression, segment); } return(result.Expression); }