You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuEfCrudDataAccess.cs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Luticate2.Auth.Utils.Business.Converters;
  6. using Luticate2.Auth.Utils.Business.Converters.ExpressionConverter;
  7. using Luticate2.Auth.Utils.Dbo;
  8. using Luticate2.Auth.Utils.Dbo.Fields;
  9. using Luticate2.Auth.Utils.Dbo.Pagination;
  10. using Luticate2.Auth.Utils.Dbo.Result;
  11. using Luticate2.Auth.Utils.Interfaces;
  12. using Microsoft.EntityFrameworkCore;
  13. using Microsoft.Extensions.DependencyInjection;
  14. namespace Luticate2.Auth.Utils.DataAccess.Crud
  15. {
  16. public class LuEfCrudDataAccess<TDbo, TModel, TDbContext> : ILuCrud<TDbo>
  17. where TModel : class
  18. where TDbContext : DbContext
  19. where TDbo : class
  20. {
  21. protected IServiceProvider ServiceProvider { get; }
  22. protected ILuConvertersAllocator ConvertersAllocator { get; }
  23. protected ILuConvertersTypeConverter ConvertersTypeConverter { get; }
  24. public LuEfCrudDataAccess(IServiceProvider serviceProvider)
  25. {
  26. ServiceProvider = serviceProvider;
  27. ConvertersAllocator = ServiceProvider.GetRequiredService<ILuConvertersAllocator>();
  28. ConvertersTypeConverter = ServiceProvider.GetRequiredService<ILuConvertersTypeConverter>();
  29. }
  30. protected virtual LuConvertersOptions GetOptions()
  31. {
  32. return new LuConvertersOptions
  33. {
  34. Allocator = ConvertersAllocator,
  35. Parameters = new Dictionary<ParameterExpression, Expression>(),
  36. TypeConverter = ConvertersTypeConverter
  37. };// TODO
  38. }
  39. protected virtual LuResult<TModel> ConvertDboToModel(LuPartialFieldsDbo partialInput, TDbo dbo)
  40. {
  41. var copier = ServiceProvider.GetService<ILuObjectConverter<TDbo, TModel>>();
  42. if (copier == null)
  43. {
  44. return LuResult<TModel>.Error(LuStatus.InternalError.ToInt(),
  45. $"Could not get service: {nameof(ILuObjectConverter)}<{typeof(TDbo).Name}, {typeof(TModel).Name}>");
  46. }
  47. var options = GetOptions();
  48. var dstObjResult = options.Allocator.GetInstance(typeof(TModel));
  49. if (!dstObjResult)
  50. {
  51. return dstObjResult.To<TModel>();
  52. }
  53. var dstObj = dstObjResult.Data;
  54. var result = copier.Convert(dbo, dstObj, new LuFieldDbo(), partialInput, GetOptions());
  55. return result.Select(o => o as TModel);
  56. }
  57. protected virtual LuResult<TDbo> ConvertModelToDbo(LuPartialFieldsDbo partialResponse, TModel model)
  58. {
  59. var copier = ServiceProvider.GetService<ILuObjectConverter<TModel, TDbo>>();
  60. if (copier == null)
  61. {
  62. return LuResult<TDbo>.Error(LuStatus.InternalError.ToInt(),
  63. $"Could not get service: {nameof(ILuObjectConverter)}<{typeof(TModel).Name}, {typeof(TDbo).Name}>");
  64. }
  65. var options = GetOptions();
  66. var dstObjResult = options.Allocator.GetInstance(typeof(TDbo));
  67. if (!dstObjResult)
  68. {
  69. return dstObjResult.To<TDbo>();
  70. }
  71. var dstObj = dstObjResult.Data;
  72. var result = copier.Convert(model, dstObj, new LuFieldDbo(), partialResponse, GetOptions());
  73. return result.Select(o => o as TDbo);
  74. }
  75. protected virtual LuResult<T> HandleError<T>(Exception e)
  76. {
  77. return LuResult<T>.Error(LuStatus.DbError.ToInt(), e);
  78. }
  79. protected LuResult<T> Execute<T>(Func<TDbContext, DbSet<TModel>, LuResult<T>> action)
  80. {
  81. try
  82. {
  83. using (var db = ServiceProvider.GetService<TDbContext>())
  84. {
  85. return action(db, db.Set<TModel>());
  86. }
  87. }
  88. catch (Exception e)
  89. {
  90. var result = HandleError<T>(e);
  91. return result;
  92. }
  93. }
  94. protected virtual LuResult<IQueryable<TModel>> Include(LuPartialFieldsDbo partialResponse, IQueryable<TModel> queryable)
  95. {
  96. return LuResult<IQueryable<TModel>>.Ok(queryable);
  97. }
  98. protected virtual LuResult<IQueryable<TModel>> Filter(LuFilterDbo filter, IQueryable<TModel> queryable)
  99. {
  100. if (filter.Expression == null)
  101. {
  102. return LuResult<IQueryable<TModel>>.Ok(queryable);
  103. }
  104. var lamdbaDbo = (Expression<Func<TDbo, bool>>) filter.Expression;
  105. var options = GetOptions();
  106. var converter = new LuExpressionConverterVisitor(options, ServiceProvider);
  107. var lamdbaModel = converter.Visit(lamdbaDbo) as Expression<Func<TModel, bool>>;// TODO Handle errors
  108. return LuResult<IQueryable<TModel>>.Ok(queryable.Where(lamdbaModel));
  109. }
  110. protected virtual LuResult<IQueryable<TModel>> OrderByField(LuOrderByFieldDbo orderByField, IQueryable<TModel> queryable)
  111. {
  112. var lamdbaDbo = (Expression<Func<TDbo, object>>) orderByField.Expression;
  113. var options = GetOptions();
  114. var converter = new LuExpressionConverterVisitor(options, ServiceProvider);
  115. var lamdbaModel = converter.Visit(lamdbaDbo) as Expression<Func<TModel, object>>;
  116. IOrderedQueryable<TModel> ordered = null;
  117. if (queryable is IOrderedQueryable<TModel> orderedQueryable)
  118. {
  119. if (orderByField.Asc)
  120. {
  121. ordered = orderedQueryable.ThenBy(lamdbaModel);
  122. }
  123. else
  124. {
  125. ordered = orderedQueryable.ThenByDescending(lamdbaModel);
  126. }
  127. }
  128. else
  129. {
  130. if (orderByField.Asc)
  131. {
  132. ordered = queryable.OrderBy(lamdbaModel);
  133. }
  134. else
  135. {
  136. ordered = queryable.OrderByDescending(lamdbaModel);
  137. }
  138. }
  139. return LuResult<IQueryable<TModel>>.Ok(ordered);
  140. // var expressionBuilder = ServiceProvider.GetService<ILuDboModelExpressionConverter<TDbo, TModel>>();
  141. // var expressionResult = expressionBuilder.ConvertLamdba<TModel>(orderByfield.);
  142. // if (!expressionResult)
  143. // {
  144. // return expressionResult.To<IQueryable<TModel>>();
  145. // }
  146. //
  147. // var expression = expressionResult.Data;
  148. // var expressionNoConvert = LuExpressionUtils.GetFromConvert(expression);
  149. //
  150. // var ordered = queryable.OrderBy(expressionNoConvert);
  151. //
  152. // return LuResult<IQueryable<TModel>>.Ok(ordered);
  153. // return LuResult<IQueryable<TModel>>.Ok(queryable);
  154. }
  155. protected virtual LuResult<IQueryable<TModel>> OrderBy(LuOrderByDbo orderBy, IQueryable<TModel> queryable)
  156. {
  157. var ordered = queryable;
  158. foreach (var field in orderBy.OrderByFields)
  159. {
  160. var orderedResult = OrderByField(field, ordered);
  161. if (!orderedResult)
  162. {
  163. return orderedResult.To<IQueryable<TModel>>();
  164. }
  165. ordered = orderedResult.Data;
  166. }
  167. return LuResult<IQueryable<TModel>>.Ok(ordered ?? queryable);
  168. }
  169. protected virtual LuResult<IQueryable<TModel>> Paginate(int page, int perPage, IQueryable<TModel> queryable)
  170. {
  171. var paginated = queryable.Skip(page * perPage).Take(perPage);
  172. return LuResult<IQueryable<TModel>>.Ok(paginated);
  173. }
  174. public virtual LuResult<IList<TDbo>> Create(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable<TDbo> dbos)
  175. {
  176. throw new NotImplementedException();
  177. }
  178. public virtual LuResult<LuPaginatedDbo<TDbo>> Read(LuPartialFieldsDbo partialResponse, LuPaginatedParamsDbo paginationParams)
  179. {
  180. var result = Execute((context, set) =>
  181. {
  182. var includeResult = Include(partialResponse, set);
  183. if (!includeResult)
  184. {
  185. return includeResult.To<LuPaginatedDbo<TDbo>>();
  186. }
  187. var included = includeResult.Data;
  188. var orderByResult = OrderBy(paginationParams.OrderBy, included);
  189. if (!orderByResult)
  190. {
  191. return orderByResult.To<LuPaginatedDbo<TDbo>>();
  192. }
  193. var ordered = orderByResult.Data;
  194. var filteredResult = Filter(paginationParams.Filter, ordered);
  195. if (!filteredResult)
  196. {
  197. return filteredResult.To<LuPaginatedDbo<TDbo>>();
  198. }
  199. var filtered = filteredResult.Data;
  200. var count = filtered.Count();
  201. var paginatedResult = Paginate(paginationParams.Page, paginationParams.PerPage, filtered);
  202. if (!paginatedResult)
  203. {
  204. return paginatedResult.To<LuPaginatedDbo<TDbo>>();
  205. }
  206. var paginated = paginatedResult.Data;
  207. var data = paginated.AsEnumerable().Select(model =>
  208. {
  209. var convertResult = ConvertModelToDbo(partialResponse, model); // TODO Handle error
  210. return convertResult.Data;
  211. }).ToList();
  212. return LuResult<LuPaginatedDbo<TDbo>>.Ok(new LuPaginatedDbo<TDbo>
  213. {
  214. Count = count,
  215. Data = data
  216. });
  217. });
  218. return result;
  219. }
  220. public virtual LuResult<IList<TDbo>> Update(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable<TDbo> dbos)
  221. {
  222. throw new NotImplementedException();
  223. }
  224. public virtual LuResult<IList<TDbo>> Delete(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable<TDbo> dbos)
  225. {
  226. throw new NotImplementedException();
  227. }
  228. }
  229. }