123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- using Microsoft.EntityFrameworkCore;
- using System.Collections;
- using System.Linq.Expressions;
- using System.Text;
- using System.Transactions;
- using Masuit.Tools.Systems;
- using Masuit.Tools.Reflection;
- using Microsoft.EntityFrameworkCore.Query.Internal;
- using Microsoft.EntityFrameworkCore.Query;
- namespace Masuit.Tools.Core;
- public static class DbContextExt
- {
- /// <summary>
- /// 获取变化的实体信息
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry<T>> GetChanges<T>(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e is { State: EntityState.Modified, Entity: T }).Select(e =>
- {
- NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry<T>
- {
- EntityState = e.State,
- Entity = (T)e.Entity,
- EntityType = e.OriginalValues.EntityType.ClrType,
- 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
- {
- PropertyInfo = t1.Property.PropertyInfo,
- OriginalValue = t1.Value,
- CurrentValue = t2.Value,
- IsPrimaryKey = t1.Property.IsPrimaryKey(),
- IsForeignKey = t1.Property.IsForeignKey()
- }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList()
- };
- });
- }
- /// <summary>
- /// 获取变化的实体信息
- /// </summary>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry> GetChanges(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).Select(e =>
- {
- NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry
- {
- EntityState = e.State,
- Entity = e.Entity,
- EntityType = e.OriginalValues.EntityType.ClrType,
- 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
- {
- PropertyInfo = t1.Property.PropertyInfo,
- OriginalValue = t1.Value,
- CurrentValue = t2.Value,
- IsPrimaryKey = t1.Property.IsPrimaryKey(),
- IsForeignKey = t1.Property.IsForeignKey()
- }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList()
- };
- });
- }
- /// <summary>
- /// 获取添加的实体信息
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry<T>> GetAdded<T>(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is T).Select(e =>
- {
- NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry<T>
- {
- EntityState = e.State,
- Entity = (T)e.Entity,
- EntityType = e.CurrentValues.EntityType.ClrType,
- ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo()
- {
- PropertyInfo = p.PropertyInfo,
- CurrentValue = currentObject[p.PropertyInfo?.Name],
- IsPrimaryKey = p.IsPrimaryKey(),
- IsForeignKey = p.IsForeignKey(),
- }).ToList()
- };
- });
- }
- /// <summary>
- /// 获取添加的实体信息
- /// </summary>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry> GetAdded(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added).Select(e =>
- {
- NullableDictionary<string, object> currentObject = e.CurrentValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry
- {
- EntityState = e.State,
- Entity = e.Entity,
- EntityType = e.CurrentValues.EntityType.ClrType,
- ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo
- {
- PropertyInfo = p.PropertyInfo,
- CurrentValue = currentObject[p.PropertyInfo?.Name],
- IsPrimaryKey = p.IsPrimaryKey(),
- IsForeignKey = p.IsForeignKey(),
- }).ToList()
- };
- });
- }
- /// <summary>
- /// 获取移除的实体信息
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry<T>> GetRemoved<T>(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted && e.Entity is T).Select(e =>
- {
- NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry<T>
- {
- EntityState = e.State,
- Entity = (T)e.Entity,
- EntityType = e.OriginalValues.EntityType.ClrType,
- ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo
- {
- PropertyInfo = p.PropertyInfo,
- OriginalValue = originalObject[p.PropertyInfo?.Name],
- IsPrimaryKey = p.IsPrimaryKey(),
- IsForeignKey = p.IsForeignKey(),
- }).ToList()
- };
- });
- }
- /// <summary>
- /// 获取移除的实体信息
- /// </summary>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry> GetRemoved(this DbContext db)
- {
- return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted).Select(e =>
- {
- NullableDictionary<string, object> originalObject = e.OriginalValues.ToObject() as Dictionary<string, object> ?? new NullableDictionary<string, object>();
- return new ChangeEntry
- {
- EntityState = e.State,
- Entity = e.Entity,
- EntityType = e.OriginalValues.EntityType.ClrType,
- ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo
- {
- PropertyInfo = p.PropertyInfo,
- OriginalValue = originalObject[p.PropertyInfo?.Name],
- IsPrimaryKey = p.IsPrimaryKey(),
- IsForeignKey = p.IsForeignKey(),
- }).ToList()
- };
- });
- }
- /// <summary>
- /// 获取所有的变更信息
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry<T>> GetAllChanges<T>(this DbContext db)
- {
- return GetChanges<T>(db).Union(GetAdded<T>(db)).Union(GetRemoved<T>(db));
- }
- /// <summary>
- /// 获取所有的变更信息
- /// </summary>
- /// <param name="db"></param>
- /// <returns></returns>
- public static IEnumerable<ChangeEntry> GetAllChanges(this DbContext db)
- {
- return GetChanges(db).Union(GetAdded(db)).Union(GetRemoved(db));
- }
- public static IQueryable<TEntity> IncludeRecursive<TEntity>(this IQueryable<TEntity> source, int levelIndex, Expression<Func<TEntity, ICollection<TEntity>>> expression) where TEntity : class
- {
- if (levelIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(levelIndex));
- var member = (MemberExpression)expression.Body;
- var property = member.Member.Name;
- var sb = new StringBuilder();
- for (int i = 0; i < levelIndex; i++)
- {
- if (i > 0)
- sb.Append(Type.Delimiter);
- sb.Append(property);
- }
- return source.Include(sb.ToString());
- }
- public static Task<List<T>> ToListWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async (q) =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.ToListAsync(cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static List<T> ToListWithNoLock<T>(this IQueryable<T> query)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.ToList();
- scope.Complete();
- return result;
- });
- }
- public static Task<int> CountWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.CountAsync(cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static int CountWithNoLock<T>(this IQueryable<T> query)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.Count();
- scope.Complete();
- return result;
- });
- }
- public static Task<int> CountWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.CountAsync(where, cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static int CountWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.Count(where);
- scope.Complete();
- return result;
- });
- }
- public static Task<bool> AnyWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.AnyAsync(cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static bool AnyWithNoLock<T>(this IQueryable<T> query)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.Any();
- scope.Complete();
- return result;
- });
- }
- public static Task<bool> AnyWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.AnyAsync(where, cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static bool AnyWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.Any(where);
- scope.Complete();
- return result;
- });
- }
- public static Task<T> FirstOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.FirstOrDefaultAsync(where, cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static T FirstOrDefaultWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.FirstOrDefault(where);
- scope.Complete();
- return result;
- });
- }
- public static Task<T> FirstOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.FirstOrDefaultAsync(cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static T FirstOrDefaultWithNoLock<T>(this IQueryable<T> query)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.FirstOrDefault();
- scope.Complete();
- return result;
- });
- }
- public static Task<T> SingleOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.SingleOrDefaultAsync(where, cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static T SingleOrDefaultWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.SingleOrDefault(where);
- scope.Complete();
- return result;
- });
- }
- public static Task<T> SingleOrDefaultWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.SingleOrDefaultAsync(cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static T SingleOrDefaultWithNoLock<T>(this IQueryable<T> query)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = q.SingleOrDefault();
- scope.Complete();
- return result;
- });
- }
- public static Task<bool> AllWithNoLockAsync<T>(this IQueryable<T> query, Expression<Func<T, bool>> where, CancellationToken cancellationToken = default)
- {
- return ExecuteStrategyAsync(query, async q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = await q.AllAsync(where, cancellationToken);
- scope.Complete();
- return result;
- });
- }
- public static bool AllWithNoLock<T>(this IQueryable<T> query, Expression<Func<T, bool>> where)
- {
- return ExecuteStrategy(query, q =>
- {
- using var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- }, TransactionScopeAsyncFlowOption.Enabled);
- var result = query.All(where);
- scope.Complete();
- return result;
- });
- }
- public static T NoLock<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, T> func) where TDbContext : DbContext
- {
- var strategy = dbContext.Database.CreateExecutionStrategy();
- return strategy.Execute(() =>
- {
- var transactionOptions = new TransactionOptions
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- };
- using var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions);
- var result = func(dbContext);
- scope.Complete();
- return result;
- });
- }
- public static Task<T> NoLock<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, Task<T>> func) where TDbContext : DbContext
- {
- var strategy = dbContext.Database.CreateExecutionStrategy();
- return strategy.ExecuteAsync(async () =>
- {
- var transactionOptions = new TransactionOptions
- {
- IsolationLevel = IsolationLevel.ReadUncommitted
- };
- using var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions);
- var result = await func(dbContext);
- scope.Complete();
- return result;
- });
- }
- public static T ExecuteStrategy<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, T> func) where TDbContext : DbContext
- {
- var strategy = dbContext.Database.CreateExecutionStrategy();
- return strategy.Execute(() => func(dbContext));
- }
- public static Task<T> ExecuteStrategy<T, TDbContext>(this TDbContext dbContext, Func<TDbContext, Task<T>> func) where TDbContext : DbContext
- {
- var strategy = dbContext.Database.CreateExecutionStrategy();
- return strategy.ExecuteAsync(() => func(dbContext));
- }
- public static TResult ExecuteStrategy<T, TResult>(this IQueryable<T> query, Func<IQueryable<T>, TResult> func)
- {
- if (query.Provider is not EntityQueryProvider)
- {
- return func(query);
- }
- var dependencies = query.Provider.GetField<QueryCompiler>("_queryCompiler").GetField<CompiledQueryCacheKeyGenerator>("_compiledQueryCacheKeyGenerator").GetField<CompiledQueryCacheKeyGeneratorDependencies>("Dependencies");
- #if NETSTANDARD2_0
- var context = dependencies.Context.Context;
- #else
- var context = dependencies.CurrentContext.Context;
- #endif
- var strategy = context.Database.CreateExecutionStrategy();
- return strategy.Execute(() => func(query));
- }
- public static Task<TResult> ExecuteStrategyAsync<T, TResult>(this IQueryable<T> query, Func<IQueryable<T>, Task<TResult>> func)
- {
- if (query.Provider is not EntityQueryProvider)
- {
- return func(query);
- }
- var dependencies = query.Provider.GetField<QueryCompiler>("_queryCompiler").GetField<CompiledQueryCacheKeyGenerator>("_compiledQueryCacheKeyGenerator").GetField<CompiledQueryCacheKeyGeneratorDependencies>("Dependencies");
- #if NETSTANDARD2_0
- var context = dependencies.Context.Context;
- #else
- var context = dependencies.CurrentContext.Context;
- #endif
- var strategy = context.Database.CreateExecutionStrategy();
- return strategy.ExecuteAsync(() => func(query));
- }
- }
|