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
}
}