123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using Luticate2.Auth.Utils.Business.Converters;
- using Luticate2.Auth.Utils.Business.Converters.ExpressionConverter;
- using Luticate2.Auth.Utils.Dbo;
- using Luticate2.Auth.Utils.Dbo.Fields;
- using Luticate2.Auth.Utils.Dbo.Pagination;
- using Luticate2.Auth.Utils.Dbo.Result;
- using Luticate2.Auth.Utils.Interfaces;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.DependencyInjection;
-
- namespace Luticate2.Auth.Utils.DataAccess.Crud
- {
- public class LuEfCrudDataAccess<TDbo, TModel, TDbContext> : ILuCrud<TDbo>
- where TModel : class
- where TDbContext : DbContext
- where TDbo : class
- {
- protected IServiceProvider ServiceProvider { get; }
- protected ILuConvertersAllocator ConvertersAllocator { get; }
- protected ILuConvertersTypeConverter ConvertersTypeConverter { get; }
-
- public LuEfCrudDataAccess(IServiceProvider serviceProvider)
- {
- ServiceProvider = serviceProvider;
- ConvertersAllocator = ServiceProvider.GetRequiredService<ILuConvertersAllocator>(); // TODO Make a DbContext or DataAccess specific ILuConvertersAllocator (in case of multiple DbContext)
- ConvertersTypeConverter = ServiceProvider.GetRequiredService<ILuConvertersTypeConverter>(); // TODO same as above
- }
-
- protected virtual LuConvertersOptions GetOptions()
- {
- return new LuConvertersOptions
- {
- Allocator = ConvertersAllocator,
- Parameters = new Dictionary<ParameterExpression, Expression>(),
- TypeConverter = ConvertersTypeConverter
- };
- }
-
- protected virtual LuResult<TTypeTo> Convert<TTypeTo>(LuPartialFieldsDbo partialResponse, object dbo, LuConvertersOptions options) where TTypeTo : class
- {
- var typeTo = dbo.GetType();
- var converterType = typeof(ILuObjectConverter<,>);
- var gConverterType = converterType.MakeGenericType(typeTo, typeof(TTypeTo));
- var converter = (ILuObjectConverter) ServiceProvider.GetService(gConverterType);
- if (converter == null)
- {
- return LuResult<TTypeTo>.Error(LuStatus.InternalError.ToInt(),
- $"Could not get service: {nameof(ILuObjectConverter)}<{typeof(TDbo).Name}, {typeof(TTypeTo).Name}>");
- }
-
- var dstObjResult = options.Allocator.GetInstance(typeof(TTypeTo));
- if (!dstObjResult)
- {
- return dstObjResult.To<TTypeTo>();
- }
- var dstObj = dstObjResult.Data;
- var result = converter.Convert(dbo, dstObj, new LuFieldDbo(), partialResponse, options);
- return result.Select(o => o as TTypeTo);
- }
-
- protected virtual LuResult<IList<TTypeTo>> Convert<TTypeTo>(LuPartialFieldsDbo partialResponse, IEnumerable<object> dbos, LuConvertersOptions options) where TTypeTo : class
- {
- var dboList = new List<TTypeTo>();
- foreach (var model in dbos)
- {
- var dboResult = Convert<TTypeTo>(partialResponse, model, options);
- if (!dboResult)
- {
- return dboResult.To<IList<TTypeTo>>();
- }
- var dbo = dboResult.Data;
-
- dboList.Add(dbo);
- }
-
- return LuResult<IList<TTypeTo>>.Ok(dboList);
- }
-
- protected virtual LuResult<T> HandleError<T>(Exception e)
- {
- return LuResult<T>.Error(LuStatus.DbError.ToInt(), e);
- }
-
- protected LuResult<T> Execute<T>(Func<TDbContext, DbSet<TModel>, LuResult<T>> action)
- {
- try
- {
- using (var db = ServiceProvider.GetService<TDbContext>())
- {
- return action(db, db.Set<TModel>());
- }
- }
- catch (Exception e)
- {
- var result = HandleError<T>(e);
- return result;
- }
- }
-
- protected virtual LuResult<IQueryable<TModel>> Include(LuPartialFieldsDbo partialResponse, IQueryable<TModel> queryable)
- {
- return LuResult<IQueryable<TModel>>.Ok(queryable);
- }
-
- protected virtual LuResult<IQueryable<TModel>> Filter(LuFilterDbo filter, IQueryable<TModel> queryable, LuConvertersOptions options)
- {
- if (filter.Expression == null)
- {
- return LuResult<IQueryable<TModel>>.Ok(queryable);
- }
-
- var lambdaDbo = filter.Expression as Expression<Func<TDbo, bool>>;
-
- var converter = new LuExpressionConverterVisitor(options, ServiceProvider);
- var lambdaModel = converter.Visit(lambdaDbo) as Expression<Func<TModel, bool>>;// TODO Handle errors
- return LuResult<IQueryable<TModel>>.Ok(queryable.Where(lambdaModel));
- }
-
- protected virtual LuResult<IQueryable<TModel>> OrderByField(LuOrderByFieldDbo orderByField, IQueryable<TModel> queryable, LuConvertersOptions options)
- {
- var lambdaDbo = orderByField.Expression as Expression<Func<TDbo, object>>;
-
- var converter = new LuExpressionConverterVisitor(options, ServiceProvider);
- var lambdaModelNoConvert = converter.Visit(lambdaDbo) as LambdaExpression;// TODO Handle errors
- var lambdaModel = Expression.Lambda<Func<TModel, object>>(lambdaModelNoConvert.Body, lambdaModelNoConvert.Parameters);
-
- IOrderedQueryable<TModel> ordered;
-
- if (queryable is IOrderedQueryable<TModel> orderedQueryable)
- {
- if (orderByField.Asc)
- {
- ordered = orderedQueryable.ThenBy(lambdaModel);
- }
- else
- {
- ordered = orderedQueryable.ThenByDescending(lambdaModel);
- }
- }
- else
- {
- if (orderByField.Asc)
- {
- ordered = queryable.OrderBy(lambdaModel);
- }
- else
- {
- ordered = queryable.OrderByDescending(lambdaModel);
- }
- }
-
- return LuResult<IQueryable<TModel>>.Ok(ordered);
- }
-
- protected virtual LuResult<IQueryable<TModel>> OrderBy(LuOrderByDbo orderBy, IQueryable<TModel> queryable, LuConvertersOptions options)
- {
- var ordered = queryable;
- foreach (var field in orderBy.OrderByFields)
- {
- var orderedResult = OrderByField(field, ordered, options);
- if (!orderedResult)
- {
- return orderedResult.To<IQueryable<TModel>>();
- }
-
- ordered = orderedResult.Data;
- }
-
- return LuResult<IQueryable<TModel>>.Ok(ordered ?? queryable);
- }
-
- protected virtual LuResult<IQueryable<TModel>> Paginate(int page, int perPage, IQueryable<TModel> queryable)
- {
- var paginated = queryable.Skip(page * perPage).Take(perPage);
- return LuResult<IQueryable<TModel>>.Ok(paginated);
- }
-
- protected virtual LuResult<LuPaginatedDbo<TModel>> Paginate(LuPaginatedParamsDbo paginationParams, LuPartialFieldsDbo partialResponse, IQueryable<TModel> set, LuConvertersOptions options)
- {
- var includeResult = Include(partialResponse, set);
- if (!includeResult)
- {
- return includeResult.To<LuPaginatedDbo<TModel>>();
- }
- var included = includeResult.Data;
-
- var orderByResult = OrderBy(paginationParams.OrderBy, included, options);
- if (!orderByResult)
- {
- return orderByResult.To<LuPaginatedDbo<TModel>>();
- }
- var ordered = orderByResult.Data;
-
- var filteredResult = Filter(paginationParams.Filter, ordered, options);
- if (!filteredResult)
- {
- return filteredResult.To<LuPaginatedDbo<TModel>>();
- }
- var filtered = filteredResult.Data;
- var count = filtered.Count();
-
- var paginatedResult = Paginate(paginationParams.Page, paginationParams.PerPage, filtered);
- if (!paginatedResult)
- {
- return paginatedResult.To<LuPaginatedDbo<TModel>>();
- }
- var paginated = paginatedResult.Data;
-
- var paginatedData = new LuPaginatedDbo<TModel>
- {
- Data = paginated.ToList(),
- Count = count
- };
-
- return LuResult<LuPaginatedDbo<TModel>>.Ok(paginatedData);
- }
-
- public virtual LuResult<IList<TDbo>> Create(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable<object> dbos)
- {
- var options = GetOptions();
- var addedDbos = new List<TDbo>();
- var addedModels = new List<TModel>();
- var createResult = Execute((context, set) =>
- {
- foreach (var dbo in dbos)
- {
- var convertResult = Convert<TModel>(partialInput, dbo, options);
- if (!convertResult)
- {
- return convertResult.To<bool>();
- }
-
- var model = convertResult.Data;
- set.Add(model);
- addedModels.Add(model);
- }
-
- context.SaveChanges();
-
- return LuResult<bool>.Ok(true);
- });
-
- if (!createResult)
- {
- return createResult.To<IList<TDbo>>();
- }
-
- foreach (var addedModel in addedModels)
- {
- var convertResult = Convert<TDbo>(partialResponse, addedModel, options);
- if (!convertResult)
- {
- return convertResult.To<IList<TDbo>>();
- }
- addedDbos.Add(convertResult.Data);
- }
-
- return LuResult<IList<TDbo>>.Ok(addedDbos);
- }
-
- public virtual LuResult<LuPaginatedDbo<TDbo>> Read(LuPartialFieldsDbo partialResponse, LuPaginatedParamsDbo paginationParams)
- {
- var result = Execute((context, set) =>
- {
- var options = GetOptions();
-
- var paginatedResult = Paginate(paginationParams, partialResponse, set, options);
- if (!paginatedResult)
- {
- return paginatedResult.To<LuPaginatedDbo<TDbo>>();
- }
- var paginated = paginatedResult.Data;
-
- var dboListResult = Convert<TDbo>(partialResponse, paginated.Data, options);
- if (!dboListResult)
- {
- return dboListResult.To<LuPaginatedDbo<TDbo>>();
- }
- var dboList = dboListResult.Data;
-
- var paginatedData = new LuPaginatedDbo<TDbo>
- {
- Count = paginated.Count,
- Data = dboList
- };
-
- return LuResult<LuPaginatedDbo<TDbo>>.Ok(paginatedData);
- });
- return result;
- }
-
- public virtual LuResult<IList<TDbo>> Update(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable<object> dbos)
- {
- throw new NotImplementedException();
- }
-
- public virtual LuResult<LuPaginatedDbo<TDbo>> Delete(LuPartialFieldsDbo partialResponse, LuPaginatedParamsDbo paginationParams)
- {
- var res = Execute((context, set) =>
- {
- var options = GetOptions();
-
- var paginatedResult = Paginate(paginationParams, partialResponse, set, options);
- if (!paginatedResult)
- {
- return paginatedResult.To<LuPaginatedDbo<TDbo>>();
- }
- var paginated = paginatedResult.Data;
-
- var dboListResult = Convert<TDbo>(partialResponse, paginated.Data, options);
- if (!dboListResult)
- {
- return dboListResult.To<LuPaginatedDbo<TDbo>>();
- }
- var dboList = dboListResult.Data;
-
- set.RemoveRange(paginated.Data);
- context.SaveChanges();
-
- var paginatedData = new LuPaginatedDbo<TDbo>
- {
- Count = paginated.Count,
- Data = dboList
- };
-
- return LuResult<LuPaginatedDbo<TDbo>>.Ok(paginatedData);
- });
-
- return res;
- }
- }
- }
|