using AutoMapper; using AutoMapper.Internal; using Kean.Application.Utilities.Interfaces; using Kean.Infrastructure.Database; using Kean.Infrastructure.Database.Repository.Default; using Pluralize.NET; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; namespace Kean.Application.Utilities.Implements { /// /// 增删改查通用服务实现 /// public class CrudService : ICrudService { private readonly IMapper _mapper; // 模型映射 private readonly IDefaultDb _database; // 默认数据库 private readonly IPluralize _pluralizer; // 类型名转换器 private string _typeName; // 类型名 private TypeMap _typeMap; // 类型映射 private object _schema; // 数据库对象 private Type _schemaType; // 数据库对象类型 private MethodInfo _schemaFactory; // 数据库对象工厂 /// /// 依赖注入 /// public CrudService( IMapper mapper, IDefaultDb database, IPluralize pluralizer) { _mapper = mapper; _database = database; _pluralizer = pluralizer; } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.GetCount 方法 */ public Task GetCount(string type, IDictionary parameters) { CreateSchema(type); if (parameters.Count > 0) { InvokeWhere(parameters); } return InvokeCount(); } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.GetList 方法 */ public Task> GetList(string type, IDictionary parameters, string sort, int? offset, int? limit) { CreateSchema(type); if (parameters.Count > 0) { InvokeWhere(parameters); } if (!string.IsNullOrEmpty(sort)) { InvokeOrderBy(sort); } if (offset.HasValue) { InvokeSkip(offset.Value); } if (limit.HasValue) { InvokeTake(limit.Value); } return InvokeSelect(); } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.GetItem 方法 */ public Task GetItem(string type, string id) { CreateSchema(type); InvokeWhere(new Dictionary() { [GetIdentifier().SourceMember.Name] = id }); return InvokeSingle(); } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.Create 方法 */ public Task Create(string type, IDictionary values) { CreateSchema(type); var entity = CreateEntity(values); var timestamp = DateTime.Now; _typeMap.DestinationType.GetProperty("CREATE_TIME")?.SetValue(entity, timestamp); _typeMap.DestinationType.GetProperty("UPDATE_TIME")?.SetValue(entity, timestamp); return InvokeAdd(entity); } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.Modify 方法 */ public Task Modify(string type, string id, IDictionary values) { CreateSchema(type); var entity = CreateEntity(values, id); _typeMap.DestinationType.GetProperty("UPDATE_TIME")?.SetValue(entity, DateTime.Now); return InvokeUpdate(entity); } /* * 实现 Kean.Application.Utilities.Interfaces.ICrudService.Delete 方法 */ public Task Delete(string type, IEnumerable id) { CreateSchema(type); InvokeWhere(id); return InvokeDelete(); } /* * 创建 Kean.Infrastructure.Database.ISchema 实例 */ private void CreateSchema(string type) { if (_typeName?.Equals(type, StringComparison.OrdinalIgnoreCase) != true) { _typeName = type; _typeMap = _mapper.GetMap(_pluralizer.Singularize(type)); _schemaFactory = _database.GetType().GetMethod("From", 1, Array.Empty()).MakeGenericMethod(_typeMap.DestinationType); _schemaType = _schemaFactory.ReturnType; } _schema = _schemaFactory.Invoke(_database, null); } /* * 获取标识属性 */ private PropertyMap GetIdentifier() { return _typeMap.PropertyMaps.First(m => m.DestinationMember.GetCustomAttribute() != null); } /* * 创建实体 */ private object CreateEntity(IDictionary values, string id = null) { var entity = Activator.CreateInstance(_typeMap.DestinationType); foreach (var item in _typeMap.PropertyMaps) { var property = item.DestinationMember as PropertyInfo; if (id != null && property.GetCustomAttribute() != null) { property.SetValue(entity, Convert.ChangeType(id, property.PropertyType)); continue; } var value = values.FirstOrDefault(i => item.SourceMember.Name.Equals(i.Key, StringComparison.OrdinalIgnoreCase)).Value; if (value != null) { property.SetValue(entity, Convert.ChangeType(value, property.PropertyType)); } } return entity; } /* * 调用 Single 方法 */ private Task InvokeSingle() { var singleMethod = _schemaType.GetMethod(nameof(ISchema.Single), Array.Empty()); return (singleMethod.Invoke(_schema, null) as Task).ContinueWith(task => _mapper.Map( task.GetType().GetProperty(nameof(Task.Result)).GetValue(task), _typeMap.DestinationType, _typeMap.SourceType)); } /* * 调用 Single 方法实现 Count */ private Task InvokeCount() { var delegateType = typeof(Func<,>).MakeGenericType(_typeMap.DestinationType, typeof(object)); var singleMethod = _schemaType.GetMethod(nameof(ISchema.Single), new Type[] { typeof(Expression<>).MakeGenericType(delegateType) }); return (singleMethod.Invoke(_schema, new object[] { CreateCountExpression(delegateType) }) as Task).ContinueWith(task => { var result = task.GetType().GetProperty(nameof(Task.Result)).GetValue(task) as IDictionary; return Convert.ToInt32(result.Values.First()); }); } /* * 调用 Select 方法 */ private Task> InvokeSelect() { var selectMethod = _schemaType.GetMethod(nameof(ISchema.Select), Array.Empty()); return (selectMethod.Invoke(_schema, null) as Task).ContinueWith(task => _mapper.Map( task.GetType().GetProperty(nameof(Task.Result)).GetValue(task), typeof(IEnumerable<>).MakeGenericType(_typeMap.DestinationType), typeof(IEnumerable<>).MakeGenericType(_typeMap.SourceType)) as IEnumerable); } /* * 调用 Add 方法 */ private Task InvokeAdd(object entity) { var addMethod = _schemaType.GetMethod(nameof(ISchema.Add)); return (addMethod.Invoke(_schema, new object[] { entity }) as Task).ContinueWith(task => { _database.Save(); var identifier = _typeMap.PropertyMaps.SingleOrDefault(m => m.DestinationMember.GetCustomAttribute()?.Increment == true); if (identifier == null) { return task.Result; } else { return identifier.DestinationMember.GetMemberValue(entity); } }); } /* * 调用 Update 方法 */ private Task InvokeUpdate(object entity) { var updateMethod = _schemaType.GetMethod(nameof(ISchema.Update), new Type[] { _typeMap.DestinationType, typeof(string[]) }); return (updateMethod.Invoke(_schema, new object[] { entity, new string[] { "CREATE_TIME" } }) as Task).ContinueWith(task => _database.Save()); } /* * 调用 Delete 方法 */ private Task InvokeDelete() { var deleteMethod = _schemaType.GetMethod(nameof(ISchema.Delete), Array.Empty()); return (deleteMethod.Invoke(_schema, null) as Task).ContinueWith(task => _database.Save()); } /* * 调用 Where 方法 */ private void InvokeWhere(IDictionary parameters) { var delegateType = typeof(Func<,>).MakeGenericType(_typeMap.DestinationType, typeof(bool?)); var whereMethod = _schemaType.GetMethod(nameof(ISchema.Where), new Type[] { typeof(Expression<>).MakeGenericType(delegateType) }); foreach (var item in parameters) { var expression = CreateConditionExpression(delegateType, item); if (expression != null) { whereMethod.Invoke(_schema, new object[] { expression }); } } } /* * 调用 Where 方法 */ private void InvokeWhere(IEnumerable id) { var delegateType = typeof(Func<,>).MakeGenericType(_typeMap.DestinationType, typeof(bool?)); var whereMethod = _schemaType.GetMethod(nameof(ISchema.Where), new Type[] { typeof(Expression<>).MakeGenericType(delegateType) }); var expression = CreateBatchExpression(delegateType, id); if (expression != null) { whereMethod.Invoke(_schema, new object[] { expression }); } } /* * 调用 OrderBy 方法 */ private void InvokeOrderBy(string sort) { var order = sort[0] == '~' ? Order.Descending : Order.Ascending; var column = order == Order.Descending ? sort[1..] : sort; var delegateType = typeof(Func<,>).MakeGenericType(_typeMap.DestinationType, typeof(object)); var expression = CreateColumnExpression(delegateType, column); if (expression != null) { var orderByMethod = _schemaType.GetMethod(nameof(ISchema.OrderBy), new Type[] { typeof(Expression<>).MakeGenericType(delegateType), typeof(Order) }); orderByMethod.Invoke(_schema, new object[] { expression, order }); } } /* * 调用 Skip 方法 */ private void InvokeSkip(int offset) { _schemaType.GetMethod(nameof(ISchema.Skip)) .Invoke(_schema, new object[] { offset }); } /* * 调用 Take 方法 */ private void InvokeTake(int limit) { _schemaType.GetMethod(nameof(ISchema.Take)) .Invoke(_schema, new object[] { limit }); } /* * 创建条件表达式 */ private LambdaExpression CreateConditionExpression(Type delegateType, KeyValuePair parameter) { var property = _typeMap.PropertyMaps .FirstOrDefault(p => p.SourceMember.Name.Equals(parameter.Key, StringComparison.OrdinalIgnoreCase))? .DestinationMember as PropertyInfo; if (property != null) { var argument = Expression.Parameter(_typeMap.DestinationType, "a"); return Expression.Lambda( delegateType, Expression.Convert( property.PropertyType == typeof(string) ? Expression.Call( Expression.Property(argument, property), typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string) }), Expression.Constant(parameter.Value)) : Expression.Equal( Expression.Property(argument, property), Expression.Constant(Convert.ChangeType(parameter.Value, property.PropertyType))), typeof(bool?)), argument); } return null; } /* * 创建字段表达式 */ private LambdaExpression CreateColumnExpression(Type delegateType, string column) { var property = _typeMap.PropertyMaps .FirstOrDefault(p => p.SourceMember.Name.Equals(column, StringComparison.OrdinalIgnoreCase))? .DestinationMember as PropertyInfo; if (property != null) { var argument = Expression.Parameter(_typeMap.DestinationType, "a"); return Expression.Lambda( delegateType, Expression.Convert( Expression.Property(argument, property), typeof(object)), argument); } return null; } /* * 创建计数表达式 */ private LambdaExpression CreateCountExpression(Type delegateType) { var property = _typeMap.DestinationType.GetProperties().FirstOrDefault(p => p.GetCustomAttribute() != null); var argument = Expression.Parameter(_typeMap.DestinationType, "a"); return Expression.Lambda( delegateType, Expression.Call(typeof(Function).GetMethod(nameof(Function.Count)), Expression.Convert( Expression.Property(argument, property ?? _typeMap.DestinationType.GetProperties().First()), typeof(object))), argument); } /* * 创建批量表达式 */ private LambdaExpression CreateBatchExpression(Type delegateType, IEnumerable range) { var property = _typeMap.DestinationType.GetProperties().FirstOrDefault(p => p.GetCustomAttribute() != null); var argument = Expression.Parameter(_typeMap.DestinationType, "a"); return Expression.Lambda( delegateType, Expression.Convert( Expression.Call( typeof(Enumerable).GetMethod(nameof(Enumerable.Contains), new Type[] { typeof(IEnumerable<>).MakeGenericType(Type.MakeGenericMethodParameter(0)), Type.MakeGenericMethodParameter(0) }).MakeGenericMethod(property.PropertyType), Expression.NewArrayInit(property.PropertyType, range.Select(i => Expression.Constant(Convert.ChangeType(i, property.PropertyType)))), Expression.Property(argument, property)), typeof(bool?)), argument); } } }