NavSelectHelper.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SqlSugar
  8. {
  9. internal class NavSelectHelper
  10. {
  11. internal static List<TResult> GetList<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  12. {
  13. List<TResult> result = new List <TResult>();
  14. var isSqlFunc = IsSqlFunc(expression, queryableProvider);
  15. var isClass = IsClass(expression, queryableProvider);
  16. if (isGroup(expression, queryableProvider))
  17. {
  18. var sqlfuncQueryable = queryableProvider.Clone();
  19. sqlfuncQueryable.QueryBuilder.Includes = null;
  20. result = sqlfuncQueryable
  21. .Select(expression)
  22. .ToList();
  23. var includeQueryable = queryableProvider.Clone();
  24. includeQueryable.Select(GetGroupSelect(typeof(T), queryableProvider.Context, queryableProvider.QueryBuilder));
  25. includeQueryable.QueryBuilder.NoCheckInclude = true;
  26. var mappingColumn = GetMappingColumn(expression);
  27. MegerList(result, includeQueryable.ToList(), sqlfuncQueryable.Context, mappingColumn);
  28. }
  29. else if (isSqlFunc)
  30. {
  31. result = SqlFunc(expression, queryableProvider);
  32. }
  33. else if (typeof(TResult).IsAnonymousType() && isClass == false)
  34. {
  35. result = SqlFunc(expression, queryableProvider);
  36. }
  37. else if (typeof(TResult).IsAnonymousType() && isClass == true)
  38. {
  39. result = Action(expression, queryableProvider);
  40. }
  41. else if (expression.ToString().Contains("FirstOrDefault()"))
  42. {
  43. result = Action(expression, queryableProvider);
  44. }
  45. else
  46. {
  47. try
  48. {
  49. result = SqlFunc(expression, queryableProvider);
  50. }
  51. catch (Exception ex)
  52. {
  53. try
  54. {
  55. Console.WriteLine("Select DTO error . Warning:" + ex.Message);
  56. result = Action(expression, queryableProvider);
  57. }
  58. catch
  59. {
  60. throw;
  61. }
  62. }
  63. }
  64. return result;
  65. }
  66. private static List<TResult> Action<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  67. {
  68. List<TResult> result;
  69. var entity = queryableProvider.Context.EntityMaintenance.GetEntityInfo<TResult>();
  70. var list = queryableProvider.Clone().ToList();
  71. var dt=queryableProvider.Context.Utilities.ListToDataTable(list);
  72. foreach (System.Data.DataRow item in dt.Rows)
  73. {
  74. foreach (System.Data.DataColumn columnInfo in dt.Columns)
  75. {
  76. if (columnInfo.DataType.IsClass())
  77. {
  78. if (item[columnInfo.ColumnName] == null || item[columnInfo.ColumnName] == DBNull.Value)
  79. {
  80. item[columnInfo.ColumnName] = Activator.CreateInstance(columnInfo.DataType, true);
  81. }
  82. }
  83. }
  84. }
  85. list = queryableProvider.Context.Utilities.DataTableToList<T>(dt);
  86. result = list.Select(expression.Compile()).ToList();
  87. return result;
  88. }
  89. private static List<TResult> SqlFunc<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  90. {
  91. var mappingColumn = GetMappingColumn(expression);
  92. if (mappingColumn.Any(it => it.IsError))
  93. {
  94. return Action(expression,queryableProvider);
  95. }
  96. List<TResult> result;
  97. var sqlfuncQueryable = queryableProvider.Clone();
  98. var dtoEntity = sqlfuncQueryable.Context.EntityMaintenance.GetEntityInfo<TResult>().Columns;
  99. var tableEntity = sqlfuncQueryable.Context.EntityMaintenance.GetEntityInfo<T>().Columns;
  100. var ignoreColumns = GetIgnoreColumns(dtoEntity,tableEntity);
  101. sqlfuncQueryable.QueryBuilder.Includes = null;
  102. result = sqlfuncQueryable
  103. .IgnoreColumns(ignoreColumns)
  104. .Select(expression)
  105. .ToList();
  106. var selector = GetDefaultSelector(queryableProvider.Context.EntityMaintenance.GetEntityInfo<T>(), queryableProvider.QueryBuilder);
  107. var queryable = queryableProvider.Select(selector).Clone();
  108. queryable.QueryBuilder.NoCheckInclude = true;
  109. var includeList = queryable.ToList();
  110. MegerList(result, includeList, sqlfuncQueryable.Context,mappingColumn);
  111. return result;
  112. }
  113. private static string[] GetIgnoreColumns(List<EntityColumnInfo> dtoEntity, List<EntityColumnInfo> tableEntity)
  114. {
  115. var column = (from dto in dtoEntity
  116. join tab in tableEntity on dto.PropertyInfo.PropertyType equals tab.PropertyInfo.PropertyType
  117. where tab.Navigat!=null
  118. select tab.PropertyName).Distinct().ToArray();
  119. return column;
  120. }
  121. internal static async Task<List<TResult>> GetListAsync<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  122. {
  123. return await Task.Run(()=> { return GetList(expression,queryableProvider); });
  124. }
  125. private static string GetGroupSelect(Type type,SqlSugarProvider context,QueryBuilder queryBuilder)
  126. {
  127. var entity = context.EntityMaintenance.GetEntityInfo(type);
  128. List<string> selector = new List<string>();
  129. List<EntityColumnInfo> columns = GetListNavColumns(entity);
  130. foreach (var item in columns)
  131. {
  132. if (queryBuilder.TableShortName.HasValue())
  133. {
  134. selector.Add($" min({queryBuilder.TableShortName}.{item.DbColumnName}) as {item.DbColumnName}");
  135. }
  136. else
  137. {
  138. selector.Add($" min({item.DbColumnName}) as {item.DbColumnName}");
  139. }
  140. }
  141. return string.Join(",", selector);
  142. }
  143. private static string GetDefaultSelector(EntityInfo entityInfo, QueryBuilder queryBuilder)
  144. {
  145. List<EntityColumnInfo> columns = GetListNavColumns(entityInfo);
  146. var selector = new List<string>();
  147. if (columns.Count == 0) return null;
  148. foreach (var item in columns)
  149. {
  150. if (queryBuilder.TableShortName.HasValue())
  151. {
  152. selector.Add($" {queryBuilder.TableShortName}.{item.DbColumnName} as {item.DbColumnName}");
  153. }
  154. else
  155. {
  156. selector.Add($" {item.DbColumnName} as {item.DbColumnName}");
  157. }
  158. }
  159. return string.Join(",", selector);
  160. }
  161. private static List<EntityColumnInfo> GetListNavColumns(EntityInfo entityInfo)
  162. {
  163. var list = entityInfo.Columns.Where(it => it.Navigat != null).Select(
  164. it => it.Navigat.Name
  165. ).ToArray();
  166. var list2 = entityInfo.Columns.Where(it => it.Navigat != null && it.Navigat.Name2 != null).Select(
  167. it => it.Navigat.Name2
  168. ).ToArray();
  169. var columns = entityInfo.Columns.Where(it => it.IsPrimarykey ||
  170. list.Contains(it.PropertyName) ||
  171. list2.Contains(it.PropertyName)
  172. ).ToList();
  173. return columns;
  174. }
  175. private static void MegerList<TResult, T>(List<TResult> result, List<T> includeList,SqlSugarProvider context,List<NavMappingColumn> navMappingColumns)
  176. {
  177. if (result.Count != includeList.Count) return;
  178. var columns = context.EntityMaintenance.GetEntityInfo<T>().Columns;
  179. var resColumns = context.EntityMaintenance.GetEntityInfo<TResult>().Columns;
  180. var i = 0;
  181. foreach (var item in includeList)
  182. {
  183. foreach (var column in columns)
  184. {
  185. if (column.Navigat != null)
  186. {
  187. var value = column.PropertyInfo.GetValue(item);
  188. var resColumn=resColumns
  189. .FirstOrDefault(z=>
  190. z.PropertyName.Equals(column.PropertyName)&&
  191. z.PropertyInfo.PropertyType==column.PropertyInfo.PropertyType
  192. );
  193. if (resColumn == null && navMappingColumns.Any(z => z.Value == column.PropertyName))
  194. {
  195. var mappingColumn = navMappingColumns.First(z => z.Value == column.PropertyName);
  196. resColumn = resColumns
  197. .FirstOrDefault(z =>
  198. z.PropertyName.Equals(mappingColumn.Key) &&
  199. z.PropertyInfo.PropertyType == column.PropertyInfo.PropertyType
  200. );
  201. }
  202. if (resColumn != null)
  203. {
  204. var resItem= result[i];
  205. resColumn.PropertyInfo.SetValue(resItem,value);
  206. }
  207. }
  208. }
  209. i++;
  210. }
  211. }
  212. private static bool IsClass<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  213. {
  214. var body = ExpressionTool.GetLambdaExpressionBody(expression);
  215. if (body is NewExpression)
  216. {
  217. var newExp = ((NewExpression)body);
  218. foreach (var item in newExp.Arguments)
  219. {
  220. if (item is MemberExpression)
  221. {
  222. var member = (MemberExpression)item;
  223. if (member.Type.IsClass())
  224. {
  225. return true;
  226. }
  227. }
  228. }
  229. }
  230. return false;
  231. }
  232. private static bool IsSqlFunc<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  233. {
  234. var body=ExpressionTool.GetLambdaExpressionBody(expression);
  235. if (body is NewExpression)
  236. {
  237. var newExp=((NewExpression)body);
  238. foreach (var item in newExp.Arguments)
  239. {
  240. if (item is MethodCallExpression)
  241. {
  242. var method = ((MethodCallExpression)item).Method;
  243. if (method.DeclaringType != null&& method.DeclaringType.Name=="SqlFunc")
  244. {
  245. return true;
  246. }
  247. }
  248. }
  249. }
  250. if (body is MemberInitExpression)
  251. {
  252. var newExp = ((MemberInitExpression)body);
  253. foreach (var item in newExp.Bindings)
  254. {
  255. MemberAssignment memberAssignment = (MemberAssignment)item;
  256. if (memberAssignment.Expression is MethodCallExpression)
  257. {
  258. var method = ((MethodCallExpression)memberAssignment.Expression).Method;
  259. if (method.DeclaringType != null && method.DeclaringType.Name == "SqlFunc")
  260. {
  261. return true;
  262. }
  263. }
  264. }
  265. }
  266. return false;
  267. }
  268. private static List<NavMappingColumn> GetMappingColumn(Expression expression)
  269. {
  270. var body = ExpressionTool.GetLambdaExpressionBody(expression);
  271. var parameterName=(expression as LambdaExpression).Parameters.FirstOrDefault().Name;
  272. List<NavMappingColumn> result = new List<NavMappingColumn>();
  273. if (body is NewExpression)
  274. {
  275. var index = 0;
  276. var arg = ((NewExpression)body).Arguments;
  277. var members = ((NewExpression)body).Members;
  278. foreach (var item in arg)
  279. {
  280. var name=members[index].Name;
  281. if (item is MethodCallExpression)
  282. {
  283. AddCallError(result, item, parameterName);
  284. }
  285. index++;
  286. }
  287. }
  288. else if (body is MemberInitExpression)
  289. {
  290. foreach (var item in ((MemberInitExpression)body).Bindings)
  291. {
  292. MemberAssignment memberAssignment = (MemberAssignment)item;
  293. var key= memberAssignment.Member.Name;
  294. var value = memberAssignment.Expression;
  295. if (memberAssignment.Expression is MemberExpression)
  296. {
  297. result.Add(new NavMappingColumn() { Key = key, Value = ExpressionTool.GetMemberName(memberAssignment.Expression) });
  298. }
  299. else if(memberAssignment.Expression is MethodCallExpression)
  300. {
  301. AddCallError(result, memberAssignment.Expression,parameterName);
  302. }
  303. }
  304. }
  305. return result;
  306. }
  307. private static void AddCallError(List<NavMappingColumn> result, Expression item,string parameterName)
  308. {
  309. var method = (item as MethodCallExpression);
  310. if (method.Method.Name == "ToList" && method.Arguments.Count > 0 && method.Arguments[0] is MethodCallExpression)
  311. {
  312. method = (MethodCallExpression)method.Arguments[0];
  313. }
  314. if (method.Method.Name == "Select")
  315. {
  316. if (!item.ToString().Contains("Subqueryable"))
  317. {
  318. result.Add(new NavMappingColumn() { IsError = true });
  319. }
  320. }
  321. else if (method.Method.Name == "Join")
  322. {
  323. if (item.ToString().Contains($" {parameterName}."))
  324. {
  325. result.Add(new NavMappingColumn() { IsError = true });
  326. }
  327. }
  328. }
  329. private static bool isGroup<T, TResult>(Expression<Func<T, TResult>> expression, QueryableProvider<T> queryableProvider)
  330. {
  331. var isGroup=queryableProvider.QueryBuilder.GetGroupByString.HasValue();
  332. return isGroup;
  333. }
  334. internal class NavMappingColumn
  335. {
  336. public string Key { get; set; }
  337. public string Value { get; set; }
  338. public bool IsError { get; set; }
  339. }
  340. }
  341. }