using Polly; using SQLite; using System.Application.Entities; using System.Collections.Generic; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; namespace System.Application.Repositories { /// /// 由 sqlite-net-pcl 实现的仓储层 /// public abstract class Repository : IRepository { #region https://codetraveler.io/2019/11/26/efficiently-initializing-sqlite-database/ static string? mDataBaseDirectory; /// /// 获取或设定数据库目录,默认值为 /// public static string DataBaseDirectory { get { if (string.IsNullOrWhiteSpace(mDataBaseDirectory)) mDataBaseDirectory = IOPath.AppDataDirectory; return mDataBaseDirectory; } set { mDataBaseDirectory = value; } } static SQLiteAsyncConnection GetConnection() { var dbPath = DataBaseDirectory; IOPath.DirCreateByNotExists(dbPath); dbPath = Path.Combine(dbPath, "application.dbf"); return new SQLiteAsyncConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache); } static readonly Lazy dbConnection = new Lazy(GetConnection); static SQLiteAsyncConnection DbConnection => dbConnection.Value; protected static async ValueTask GetDbConnection() { if (!DbConnection.TableMappings.Any(x => x.MappedType == typeof(T))) { // On sqlite-net v1.6.0+, enabling write-ahead logging allows for faster database execution await DbConnection.EnableWriteAheadLoggingAsync().ConfigureAwait(false); await DbConnection.CreateTablesAsync(CreateFlags.None, typeof(T)).ConfigureAwait(false); } return DbConnection; } protected static Task AttemptAndRetry(Func> action, int numRetries = 10) { return Policy.Handle().WaitAndRetryAsync(numRetries, pollyRetryAttempt).ExecuteAsync(action); static TimeSpan pollyRetryAttempt(int attemptNumber) => TimeSpan.FromMilliseconds(Math.Pow(2, attemptNumber)); } #endregion } /// public abstract class Repository : Repository, IRepository where TEntity : class, new() { protected static ValueTask GetDbConnection() => GetDbConnection(); #region 增(Insert Funs) 立即执行并返回受影响的行数 public virtual async Task InsertAsync(TEntity entity) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.InsertAsync(entity)).ConfigureAwait(false); } public virtual async Task InsertRangeAsync(IEnumerable entities) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.InsertAllAsync(entities)).ConfigureAwait(false); } #endregion #region 删(Delete Funs) 立即执行并返回受影响的行数 public virtual async Task DeleteAsync(TEntity entity) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.DeleteAsync(entity)).ConfigureAwait(false); } #endregion #region 改(Update Funs) 立即执行并返回受影响的行数 public virtual async Task UpdateAsync(TEntity entity) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.UpdateAsync(entity)).ConfigureAwait(false); } public virtual async Task UpdateRangeAsync(IEnumerable entities) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.UpdateAllAsync(entities)).ConfigureAwait(false); } #endregion #region 查(通用查询) public virtual async Task FirstOrDefaultAsync(Expression> predicate) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.FindAsync(predicate)).ConfigureAwait(false); } #endregion } /// public abstract class Repository : Repository, IRepository where TEntity : class, IEntity, new() where TPrimaryKey : IEquatable { object IGetPrimaryKey.GetPrimaryKey(TEntity entity) => GetPrimaryKey(entity); protected TPrimaryKey GetPrimaryKey(TEntity entity) { IGetPrimaryKey getPrimaryKey = this; return getPrimaryKey.GetPrimaryKey(entity); } #region 删(Delete Funs) 立即执行并返回受影响的行数 public override Task DeleteAsync(TEntity entity) { var primaryKey = GetPrimaryKey(entity); return DeleteAsync(primaryKey); } public virtual async Task DeleteAsync(TPrimaryKey primaryKey) { var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.DeleteAsync(primaryKey)).ConfigureAwait(false); } #endregion #region 查(通用查询) public virtual async ValueTask FindAsync(TPrimaryKey primaryKey) { if (IRepository.IsDefault(primaryKey)) return default; var dbConnection = await GetDbConnection().ConfigureAwait(false); return await AttemptAndRetry(() => dbConnection.FindAsync(primaryKey)).ConfigureAwait(false); } public virtual async ValueTask ExistAsync(TPrimaryKey primaryKey) { if (IRepository.IsDefault(primaryKey)) return false; var dbConnection = await GetDbConnection().ConfigureAwait(false); var count = await AttemptAndRetry(CountAsync).ConfigureAwait(false); return count > 0; Task CountAsync() => dbConnection.Table().CountAsync(IRepository.LambdaEqualId(primaryKey)); } #endregion #region 增或改(InsertOrUpdate Funs) 立即执行并返回受影响的行数 public virtual async Task<(int rowCount, DbRowExecResult result)> InsertOrUpdateAsync(TEntity entity) { var dbConnection = await GetDbConnection().ConfigureAwait(false); var rowCount = await AttemptAndRetry(() => dbConnection.InsertOrReplaceAsync(entity)).ConfigureAwait(false); return (rowCount, DbRowExecResult.InsertOrUpdate); } #endregion } }