1
1

DbContextExt.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. using Microsoft.EntityFrameworkCore;
  2. using System.Collections;
  3. using System.Linq.Expressions;
  4. using System.Text;
  5. using System.Transactions;
  6. using Masuit.Tools.Systems;
  7. using Masuit.Tools.Reflection;
  8. using Microsoft.EntityFrameworkCore.Query.Internal;
  9. using Microsoft.EntityFrameworkCore.Query;
  10. namespace Masuit.Tools.Core;
  11. public static class DbContextExt
  12. {
  13. /// <summary>
  14. /// 获取变化的实体信息
  15. /// </summary>
  16. /// <typeparam name="T"></typeparam>
  17. /// <param name="db"></param>
  18. /// <returns></returns>
  19. public static IEnumerable<ChangeEntry<T>> GetChanges<T>(this DbContext db)
  20. {
  21. return db.ChangeTracker.Entries().Where(e => e is { State: EntityState.Modified, Entity: T }).Select(e =>
  22. {
  23. NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  24. NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  25. return new ChangeEntry<T>
  26. {
  27. EntityState = e.State,
  28. Entity = (T)e.Entity,
  29. EntityType = e.OriginalValues.EntityType.ClrType,
  30. ChangeProperties = e.OriginalValues.Properties.Select(p => (Property: p, Value: originalObject[p.PropertyInfo?.Name])).Zip(e.CurrentValues.Properties.Select(p => (Property: p, Value: currentObject[p.PropertyInfo?.Name])), (t1, t2) => new ChangePropertyInfo
  31. {
  32. PropertyInfo = t1.Property.PropertyInfo,
  33. OriginalValue = t1.Value,
  34. CurrentValue = t2.Value,
  35. IsPrimaryKey = t1.Property.IsPrimaryKey(),
  36. IsForeignKey = t1.Property.IsForeignKey()
  37. }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList()
  38. };
  39. });
  40. }
  41. /// <summary>
  42. /// 获取变化的实体信息
  43. /// </summary>
  44. /// <param name="db"></param>
  45. /// <returns></returns>
  46. public static IEnumerable<ChangeEntry> GetChanges(this DbContext db)
  47. {
  48. return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).Select(e =>
  49. {
  50. NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  51. NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  52. return new ChangeEntry
  53. {
  54. EntityState = e.State,
  55. Entity = e.Entity,
  56. EntityType = e.OriginalValues.EntityType.ClrType,
  57. ChangeProperties = e.OriginalValues.Properties.Select(p => (Property: p, Value: originalObject[p.PropertyInfo?.Name])).Zip(e.CurrentValues.Properties.Select(p => (Property: p, Value: currentObject[p.PropertyInfo?.Name])), (t1, t2) => new ChangePropertyInfo
  58. {
  59. PropertyInfo = t1.Property.PropertyInfo,
  60. OriginalValue = t1.Value,
  61. CurrentValue = t2.Value,
  62. IsPrimaryKey = t1.Property.IsPrimaryKey(),
  63. IsForeignKey = t1.Property.IsForeignKey()
  64. }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList()
  65. };
  66. });
  67. }
  68. /// <summary>
  69. /// 获取添加的实体信息
  70. /// </summary>
  71. /// <typeparam name="T"></typeparam>
  72. /// <param name="db"></param>
  73. /// <returns></returns>
  74. public static IEnumerable<ChangeEntry<T>> GetAdded<T>(this DbContext db)
  75. {
  76. return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is T).Select(e =>
  77. {
  78. NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  79. return new ChangeEntry<T>
  80. {
  81. EntityState = e.State,
  82. Entity = (T)e.Entity,
  83. EntityType = e.CurrentValues.EntityType.ClrType,
  84. ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo()
  85. {
  86. PropertyInfo = p.PropertyInfo,
  87. CurrentValue = currentObject[p.PropertyInfo?.Name],
  88. IsPrimaryKey = p.IsPrimaryKey(),
  89. IsForeignKey = p.IsForeignKey(),
  90. }).ToList()
  91. };
  92. });
  93. }
  94. /// <summary>
  95. /// 获取添加的实体信息
  96. /// </summary>
  97. /// <param name="db"></param>
  98. /// <returns></returns>
  99. public static IEnumerable<ChangeEntry> GetAdded(this DbContext db)
  100. {
  101. return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added).Select(e =>
  102. {
  103. NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  104. return new ChangeEntry
  105. {
  106. EntityState = e.State,
  107. Entity = e.Entity,
  108. EntityType = e.CurrentValues.EntityType.ClrType,
  109. ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo
  110. {
  111. PropertyInfo = p.PropertyInfo,
  112. CurrentValue = currentObject[p.PropertyInfo?.Name],
  113. IsPrimaryKey = p.IsPrimaryKey(),
  114. IsForeignKey = p.IsForeignKey(),
  115. }).ToList()
  116. };
  117. });
  118. }
  119. /// <summary>
  120. /// 获取移除的实体信息
  121. /// </summary>
  122. /// <typeparam name="T"></typeparam>
  123. /// <param name="db"></param>
  124. /// <returns></returns>
  125. public static IEnumerable<ChangeEntry<T>> GetRemoved<T>(this DbContext db)
  126. {
  127. return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted && e.Entity is T).Select(e =>
  128. {
  129. NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  130. return new ChangeEntry<T>
  131. {
  132. EntityState = e.State,
  133. Entity = (T)e.Entity,
  134. EntityType = e.OriginalValues.EntityType.ClrType,
  135. ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo
  136. {
  137. PropertyInfo = p.PropertyInfo,
  138. OriginalValue = originalObject[p.PropertyInfo?.Name],
  139. IsPrimaryKey = p.IsPrimaryKey(),
  140. IsForeignKey = p.IsForeignKey(),
  141. }).ToList()
  142. };
  143. });
  144. }
  145. /// <summary>
  146. /// 获取移除的实体信息
  147. /// </summary>
  148. /// <param name="db"></param>
  149. /// <returns></returns>
  150. public static IEnumerable<ChangeEntry> GetRemoved(this DbContext db)
  151. {
  152. return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted).Select(e =>
  153. {
  154. NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
  155. return new ChangeEntry
  156. {
  157. EntityState = e.State,
  158. Entity = e.Entity,
  159. EntityType = e.OriginalValues.EntityType.ClrType,
  160. ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo
  161. {
  162. PropertyInfo = p.PropertyInfo,
  163. OriginalValue = originalObject[p.PropertyInfo?.Name],
  164. IsPrimaryKey = p.IsPrimaryKey(),
  165. IsForeignKey = p.IsForeignKey(),
  166. }).ToList()
  167. };
  168. });
  169. }
  170. /// <summary>
  171. /// 获取所有的变更信息
  172. /// </summary>
  173. /// <typeparam name="T"></typeparam>
  174. /// <param name="db"></param>
  175. /// <returns></returns>
  176. public static IEnumerable<ChangeEntry<T>> GetAllChanges<T>(this DbContext db)
  177. {
  178. return GetChanges<T>(db).Union(GetAdded<T>(db)).Union(GetRemoved<T>(db));
  179. }
  180. /// <summary>
  181. /// 获取所有的变更信息
  182. /// </summary>
  183. /// <param name="db"></param>
  184. /// <returns></returns>
  185. public static IEnumerable<ChangeEntry> GetAllChanges(this DbContext db)
  186. {
  187. return GetChanges(db).Union(GetAdded(db)).Union(GetRemoved(db));
  188. }
  189. public static IQueryable<TEntity> IncludeRecursive<TEntity>(this IQueryable<TEntity> source, int levelIndex, Expression<Func<TEntity, ICollection<TEntity>>> expression) where TEntity : class
  190. {
  191. if (levelIndex < 0)
  192. throw new ArgumentOutOfRangeException(nameof(levelIndex));
  193. var member = (MemberExpression)expression.Body;
  194. var property = member.Member.Name;
  195. var sb = new StringBuilder();
  196. for (int i = 0; i < levelIndex; i++)
  197. {
  198. if (i > 0)
  199. sb.Append(Type.Delimiter);
  200. sb.Append(property);
  201. }
  202. return source.Include(sb.ToString());
  203. }
  204. public static Task<List<T>> ToListWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
  205. {
  206. return ExecuteStrategyAsync(query, async (q) =>
  207. {
  208. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  209. {
  210. IsolationLevel = IsolationLevel.ReadUncommitted
  211. }, TransactionScopeAsyncFlowOption.Enabled);
  212. var result = await q.ToListAsync(cancellationToken);
  213. scope.Complete();
  214. return result;
  215. });
  216. }
  217. public static List<T> ToListWithNoLock<T>(this IQueryable<T> query)
  218. {
  219. return ExecuteStrategy(query, q =>
  220. {
  221. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  222. {
  223. IsolationLevel = IsolationLevel.ReadUncommitted
  224. }, TransactionScopeAsyncFlowOption.Enabled);
  225. var result = q.ToList();
  226. scope.Complete();
  227. return result;
  228. });
  229. }
  230. public static Task<int> CountWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
  231. {
  232. return ExecuteStrategyAsync(query, async q =>
  233. {
  234. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  235. {
  236. IsolationLevel = IsolationLevel.ReadUncommitted
  237. }, TransactionScopeAsyncFlowOption.Enabled);
  238. var result = await q.CountAsync(cancellationToken);
  239. scope.Complete();
  240. return result;
  241. });
  242. }
  243. public static int CountWithNoLock<T>(this IQueryable<T> query)
  244. {
  245. return ExecuteStrategy(query, q =>
  246. {
  247. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  248. {
  249. IsolationLevel = IsolationLevel.ReadUncommitted
  250. }, TransactionScopeAsyncFlowOption.Enabled);
  251. var result = q.Count();
  252. scope.Complete();
  253. return result;
  254. });
  255. }
  256. public static Task<int> CountWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
  257. {
  258. return ExecuteStrategyAsync(query, async q =>
  259. {
  260. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  261. {
  262. IsolationLevel = IsolationLevel.ReadUncommitted
  263. }, TransactionScopeAsyncFlowOption.Enabled);
  264. var result = await q.CountAsync(where, cancellationToken);
  265. scope.Complete();
  266. return result;
  267. });
  268. }
  269. public static int CountWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
  270. {
  271. return ExecuteStrategy(query, q =>
  272. {
  273. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  274. {
  275. IsolationLevel = IsolationLevel.ReadUncommitted
  276. }, TransactionScopeAsyncFlowOption.Enabled);
  277. var result = q.Count(where);
  278. scope.Complete();
  279. return result;
  280. });
  281. }
  282. public static Task<bool> AnyWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
  283. {
  284. return ExecuteStrategyAsync(query, async q =>
  285. {
  286. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  287. {
  288. IsolationLevel = IsolationLevel.ReadUncommitted
  289. }, TransactionScopeAsyncFlowOption.Enabled);
  290. var result = await q.AnyAsync(cancellationToken);
  291. scope.Complete();
  292. return result;
  293. });
  294. }
  295. public static bool AnyWithNoLock<T>(this IQueryable<T> query)
  296. {
  297. return ExecuteStrategy(query, q =>
  298. {
  299. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  300. {
  301. IsolationLevel = IsolationLevel.ReadUncommitted
  302. }, TransactionScopeAsyncFlowOption.Enabled);
  303. var result = q.Any();
  304. scope.Complete();
  305. return result;
  306. });
  307. }
  308. public static Task<bool> AnyWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
  309. {
  310. return ExecuteStrategyAsync(query, async q =>
  311. {
  312. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  313. {
  314. IsolationLevel = IsolationLevel.ReadUncommitted
  315. }, TransactionScopeAsyncFlowOption.Enabled);
  316. var result = await q.AnyAsync(where, cancellationToken);
  317. scope.Complete();
  318. return result;
  319. });
  320. }
  321. public static bool AnyWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
  322. {
  323. return ExecuteStrategy(query, q =>
  324. {
  325. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  326. {
  327. IsolationLevel = IsolationLevel.ReadUncommitted
  328. }, TransactionScopeAsyncFlowOption.Enabled);
  329. var result = q.Any(where);
  330. scope.Complete();
  331. return result;
  332. });
  333. }
  334. public static Task<T> FirstOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
  335. {
  336. return ExecuteStrategyAsync(query, async q =>
  337. {
  338. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  339. {
  340. IsolationLevel = IsolationLevel.ReadUncommitted
  341. }, TransactionScopeAsyncFlowOption.Enabled);
  342. var result = await q.FirstOrDefaultAsync(where, cancellationToken);
  343. scope.Complete();
  344. return result;
  345. });
  346. }
  347. public static T FirstOrDefaultWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
  348. {
  349. return ExecuteStrategy(query, q =>
  350. {
  351. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  352. {
  353. IsolationLevel = IsolationLevel.ReadUncommitted
  354. }, TransactionScopeAsyncFlowOption.Enabled);
  355. var result = q.FirstOrDefault(where);
  356. scope.Complete();
  357. return result;
  358. });
  359. }
  360. public static Task<T> FirstOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
  361. {
  362. return ExecuteStrategyAsync(query, async q =>
  363. {
  364. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
  365. {
  366. IsolationLevel = IsolationLevel.ReadUncommitted
  367. }, TransactionScopeAsyncFlowOption.Enabled);
  368. var result = await q.FirstOrDefaultAsync(cancellationToken);
  369. scope.Complete();
  370. return result;
  371. });
  372. }
  373. public static T FirstOrDefaultWithNoLock<T>(this IQueryable<T> query)
  374. {
  375. return ExecuteStrategy(query, q =>
  376. {
  377. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
  378. {
  379. IsolationLevel = IsolationLevel.ReadUncommitted
  380. }, TransactionScopeAsyncFlowOption.Enabled);
  381. var result = q.FirstOrDefault();
  382. scope.Complete();
  383. return result;
  384. });
  385. }
  386. public static Task<T> SingleOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
  387. {
  388. return ExecuteStrategyAsync(query, async q =>
  389. {
  390. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
  391. {
  392. IsolationLevel = IsolationLevel.ReadUncommitted
  393. }, TransactionScopeAsyncFlowOption.Enabled);
  394. var result = await q.SingleOrDefaultAsync(where, cancellationToken);
  395. scope.Complete();
  396. return result;
  397. });
  398. }
  399. public static T SingleOrDefaultWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
  400. {
  401. return ExecuteStrategy(query, q =>
  402. {
  403. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  404. {
  405. IsolationLevel = IsolationLevel.ReadUncommitted
  406. }, TransactionScopeAsyncFlowOption.Enabled);
  407. var result = q.SingleOrDefault(where);
  408. scope.Complete();
  409. return result;
  410. });
  411. }
  412. public static Task<T> SingleOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
  413. {
  414. return ExecuteStrategyAsync(query, async q =>
  415. {
  416. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  417. {
  418. IsolationLevel = IsolationLevel.ReadUncommitted
  419. }, TransactionScopeAsyncFlowOption.Enabled);
  420. var result = await q.SingleOrDefaultAsync(cancellationToken);
  421. scope.Complete();
  422. return result;
  423. });
  424. }
  425. public static T SingleOrDefaultWithNoLock<T>(this IQueryable<T> query)
  426. {
  427. return ExecuteStrategy(query, q =>
  428. {
  429. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  430. {
  431. IsolationLevel = IsolationLevel.ReadUncommitted
  432. }, TransactionScopeAsyncFlowOption.Enabled);
  433. var result = q.SingleOrDefault();
  434. scope.Complete();
  435. return result;
  436. });
  437. }
  438. public static Task<bool> AllWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
  439. {
  440. return ExecuteStrategyAsync(query, async q =>
  441. {
  442. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  443. {
  444. IsolationLevel = IsolationLevel.ReadUncommitted
  445. }, TransactionScopeAsyncFlowOption.Enabled);
  446. var result = await q.AllAsync(where, cancellationToken);
  447. scope.Complete();
  448. return result;
  449. });
  450. }
  451. public static bool AllWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
  452. {
  453. return ExecuteStrategy(query, q =>
  454. {
  455. using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
  456. {
  457. IsolationLevel = IsolationLevel.ReadUncommitted
  458. }, TransactionScopeAsyncFlowOption.Enabled);
  459. var result = query.All(where);
  460. scope.Complete();
  461. return result;
  462. });
  463. }
  464. public static T NoLock<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, T> func) where TDbContext : DbContext
  465. {
  466. var strategy = dbContext.Database.CreateExecutionStrategy();
  467. return strategy.Execute(() =>
  468. {
  469. var transactionOptions = new TransactionOptions
  470. {
  471. IsolationLevel = IsolationLevel.ReadUncommitted
  472. };
  473. using var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions);
  474. var result = func(dbContext);
  475. scope.Complete();
  476. return result;
  477. });
  478. }
  479. public static Task<T> NoLock<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, Task<T>> func) where TDbContext : DbContext
  480. {
  481. var strategy = dbContext.Database.CreateExecutionStrategy();
  482. return strategy.ExecuteAsync(async () =>
  483. {
  484. var transactionOptions = new TransactionOptions
  485. {
  486. IsolationLevel = IsolationLevel.ReadUncommitted
  487. };
  488. using var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions);
  489. var result = await func(dbContext);
  490. scope.Complete();
  491. return result;
  492. });
  493. }
  494. public static T ExecuteStrategy<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, T> func) where TDbContext : DbContext
  495. {
  496. var strategy = dbContext.Database.CreateExecutionStrategy();
  497. return strategy.Execute(() => func(dbContext));
  498. }
  499. public static Task<T> ExecuteStrategy<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, Task<T>> func) where TDbContext : DbContext
  500. {
  501. var strategy = dbContext.Database.CreateExecutionStrategy();
  502. return strategy.ExecuteAsync(() => func(dbContext));
  503. }
  504. public static TResult ExecuteStrategy<T, TResult>(this IQueryable<T> query, Func<IQueryable<T>, TResult> func)
  505. {
  506. if (query.Provider is not EntityQueryProvider)
  507. {
  508. return func(query);
  509. }
  510. var dependencies = query.Provider.GetField<QueryCompiler>("_queryCompiler").GetField<CompiledQueryCacheKeyGenerator>("_compiledQueryCacheKeyGenerator").GetField<CompiledQueryCacheKeyGeneratorDependencies>("Dependencies");
  511. #if NETSTANDARD2_0
  512. var context = dependencies.Context.Context;
  513. #else
  514. var context = dependencies.CurrentContext.Context;
  515. #endif
  516. var strategy = context.Database.CreateExecutionStrategy();
  517. return strategy.Execute(() => func(query));
  518. }
  519. public static Task<TResult> ExecuteStrategyAsync<T, TResult>(this IQueryable<T> query, Func<IQueryable<T>, Task<TResult>> func)
  520. {
  521. if (query.Provider is not EntityQueryProvider)
  522. {
  523. return func(query);
  524. }
  525. var dependencies = query.Provider.GetField<QueryCompiler>("_queryCompiler").GetField<CompiledQueryCacheKeyGenerator>("_compiledQueryCacheKeyGenerator").GetField<CompiledQueryCacheKeyGeneratorDependencies>("Dependencies");
  526. #if NETSTANDARD2_0
  527. var context = dependencies.Context.Context;
  528. #else
  529. var context = dependencies.CurrentContext.Context;
  530. #endif
  531. var strategy = context.Database.CreateExecutionStrategy();
  532. return strategy.ExecuteAsync(() => func(query));
  533. }
  534. }