DbContextExt.cs 24 KB

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