FreeSql.DbContext 融合 Repository + UnitOfWork

This commit is contained in:
28810 2019-03-30 19:11:17 +08:00
parent 496750da94
commit a7e06843a9
15 changed files with 222 additions and 264 deletions

View File

@ -13,8 +13,9 @@ namespace FreeSql {
internal IFreeSql _orm; internal IFreeSql _orm;
internal IFreeSql _fsql => _orm ?? throw new ArgumentNullException("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql"); internal IFreeSql _fsql => _orm ?? throw new ArgumentNullException("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql");
UnitOfWork _uowPriv; IUnitOfWork _uowPriv;
internal UnitOfWork _uow => _uowPriv ?? (_uowPriv = new UnitOfWork(_fsql)); internal IUnitOfWork _uow => _isUseUnitOfWork ? (_uowPriv ?? (_uowPriv = new UnitOfWork(_fsql))) : null;
internal bool _isUseUnitOfWork = true; //不使用工作单元事务
static ConcurrentDictionary<Type, PropertyInfo[]> _dicGetDbSetProps = new ConcurrentDictionary<Type, PropertyInfo[]>(); static ConcurrentDictionary<Type, PropertyInfo[]> _dicGetDbSetProps = new ConcurrentDictionary<Type, PropertyInfo[]>();
protected DbContext() { protected DbContext() {
@ -41,15 +42,14 @@ namespace FreeSql {
} }
Dictionary<Type, object> _dicSet = new Dictionary<Type, object>(); protected Dictionary<Type, object> _dicSet = new Dictionary<Type, object>();
public DbSet<TEntity> Set<TEntity>() where TEntity : class => this.Set(typeof(TEntity)) as DbSet<TEntity>; public DbSet<TEntity> Set<TEntity>() where TEntity : class => this.Set(typeof(TEntity)) as DbSet<TEntity>;
public object Set(Type entityType) { public virtual object Set(Type entityType) {
if (_dicSet.ContainsKey(entityType)) return _dicSet[entityType]; if (_dicSet.ContainsKey(entityType)) return _dicSet[entityType];
var sd = Activator.CreateInstance(typeof(BaseDbSet<>).MakeGenericType(entityType), this); var sd = Activator.CreateInstance(typeof(DbContextDbSet<>).MakeGenericType(entityType), this);
_dicSet.Add(entityType, sd); _dicSet.Add(entityType, sd);
return sd; return sd;
} }
protected Dictionary<string, object> AllSets { get; } = new Dictionary<string, object>(); protected Dictionary<string, object> AllSets { get; } = new Dictionary<string, object>();
internal class ExecCommandInfo { internal class ExecCommandInfo {
@ -60,7 +60,7 @@ namespace FreeSql {
} }
internal enum ExecCommandInfoType { Insert, Update, Delete } internal enum ExecCommandInfoType { Insert, Update, Delete }
Queue<ExecCommandInfo> _actions = new Queue<ExecCommandInfo>(); Queue<ExecCommandInfo> _actions = new Queue<ExecCommandInfo>();
internal long _affrows = 0; internal int _affrows = 0;
internal void EnqueueAction(ExecCommandInfoType actionType, object dbSet, Type stateType, object state) { internal void EnqueueAction(ExecCommandInfoType actionType, object dbSet, Type stateType, object state) {
_actions.Enqueue(new ExecCommandInfo { actionType = actionType, dbSet = dbSet, stateType = stateType, state = state }); _actions.Enqueue(new ExecCommandInfo { actionType = actionType, dbSet = dbSet, stateType = stateType, state = state });
@ -73,7 +73,11 @@ namespace FreeSql {
public void Dispose() { public void Dispose() {
if (_isdisposed) return; if (_isdisposed) return;
try { try {
_uow.Rollback(); _actions.Clear();
_dicSet.Clear();
AllSets.Clear();
_uow?.Rollback();
} finally { } finally {
_isdisposed = true; _isdisposed = true;
GC.SuppressFinalize(this); GC.SuppressFinalize(this);

View File

@ -11,14 +11,17 @@ using System.Threading.Tasks;
namespace FreeSql { namespace FreeSql {
partial class DbContext { partial class DbContext {
async public Task<long> SaveChangesAsync() { async public Task<int> SaveChangesAsync() {
await ExecCommandAsync(); await ExecCommandAsync();
_uow.Commit(); _uow?.Commit();
return _affrows; var ret = _affrows;
_affrows = 0;
return ret;
} }
static Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>> _dicExecCommandDbContextBetchAsync = new Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>>(); static Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>> _dicExecCommandDbContextBetchAsync = new Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>>();
async internal Task ExecCommandAsync() { async internal Task ExecCommandAsync() {
if (_actions.Any() == false) return;
ExecCommandInfo oldinfo = null; ExecCommandInfo oldinfo = null;
var states = new List<object>(); var states = new List<object>();

View File

@ -10,14 +10,17 @@ using System.Linq.Expressions;
namespace FreeSql { namespace FreeSql {
partial class DbContext { partial class DbContext {
public long SaveChanges() { public int SaveChanges() {
ExecCommand(); ExecCommand();
_uow.Commit(); _uow?.Commit();
return _affrows; var ret = _affrows;
_affrows = 0;
return ret;
} }
static Dictionary<Type, Dictionary<string, Func<object, object[], int>>> _dicExecCommandDbContextBetch = new Dictionary<Type, Dictionary<string, Func<object, object[], int>>>(); static Dictionary<Type, Dictionary<string, Func<object, object[], int>>> _dicExecCommandDbContextBetch = new Dictionary<Type, Dictionary<string, Func<object, object[], int>>>();
internal void ExecCommand() { internal void ExecCommand() {
if (_actions.Any() == false) return;
ExecCommandInfo oldinfo = null; ExecCommandInfo oldinfo = null;
var states = new List<object>(); var states = new List<object>();

View File

@ -7,29 +7,41 @@ using System.Linq.Expressions;
namespace FreeSql { namespace FreeSql {
internal class BaseDbSet<TEntity> : DbSet<TEntity> where TEntity : class { internal class DbContextDbSet<TEntity> : DbSet<TEntity> where TEntity : class {
public BaseDbSet(DbContext ctx) { public DbContextDbSet(DbContext ctx) {
if (ctx != null) { _ctx = ctx;
_ctx = ctx; _uow = ctx._uow;
_uow = ctx._uow; _fsql = ctx._fsql;
_fsql = ctx._fsql;
}
} }
} }
public abstract partial class DbSet<TEntity> where TEntity : class { public abstract partial class DbSet<TEntity> : IDisposable where TEntity : class {
internal DbContext _ctx; internal DbContext _ctx;
internal UnitOfWork _uow; internal IUnitOfWork _uow;
internal IFreeSql _fsql; internal IFreeSql _fsql;
bool IsNoneDbContext => _ctx == null;
protected virtual ISelect<TEntity> OrmSelect(object dywhere) { protected virtual ISelect<TEntity> OrmSelect(object dywhere) {
DbContextExecCommand(); //查询前先提交,否则会出脏读 DbContextExecCommand(); //查询前先提交,否则会出脏读
return _fsql.Select<TEntity>(dywhere).WithTransaction(_uow?.GetOrBeginTransaction(false)).TrackToList(TrackToList); return _fsql.Select<TEntity>(dywhere).WithTransaction(_uow?.GetOrBeginTransaction(false)).TrackToList(TrackToList);
} }
~DbSet() {
this.Dispose();
}
bool _isdisposed = false;
public void Dispose() {
if (_isdisposed) return;
try {
this._dicUpdateTimes.Clear();
this._states.Clear();
} finally {
_isdisposed = true;
GC.SuppressFinalize(this);
}
}
protected virtual IInsert<TEntity> OrmInsert() => _fsql.Insert<TEntity>().WithTransaction(_uow?.GetOrBeginTransaction()); protected virtual IInsert<TEntity> OrmInsert() => _fsql.Insert<TEntity>().WithTransaction(_uow?.GetOrBeginTransaction());
protected virtual IInsert<TEntity> OrmInsert(TEntity data) => _fsql.Insert<TEntity>(data).WithTransaction(_uow?.GetOrBeginTransaction()); protected virtual IInsert<TEntity> OrmInsert(TEntity data) => _fsql.Insert<TEntity>(data).WithTransaction(_uow?.GetOrBeginTransaction());
protected virtual IInsert<TEntity> OrmInsert(IEnumerable<TEntity> data) => _fsql.Insert<TEntity>(data).WithTransaction(_uow?.GetOrBeginTransaction()); protected virtual IInsert<TEntity> OrmInsert(IEnumerable<TEntity> data) => _fsql.Insert<TEntity>(data).WithTransaction(_uow?.GetOrBeginTransaction());
@ -38,12 +50,10 @@ namespace FreeSql {
protected virtual IDelete<TEntity> OrmDelete(object dywhere) => _fsql.Delete<TEntity>(dywhere).WithTransaction(_uow?.GetOrBeginTransaction()); protected virtual IDelete<TEntity> OrmDelete(object dywhere) => _fsql.Delete<TEntity>(dywhere).WithTransaction(_uow?.GetOrBeginTransaction());
internal void EnqueueToDbContext(DbContext.ExecCommandInfoType actionType, EntityState state) { internal void EnqueueToDbContext(DbContext.ExecCommandInfoType actionType, EntityState state) {
if (IsNoneDbContext == false) _ctx.EnqueueAction(actionType, this, typeof(EntityState), state);
_ctx.EnqueueAction(actionType, this, typeof(EntityState), state);
} }
internal void IncrAffrows(long affrows) { internal void IncrAffrows(int affrows) {
if (IsNoneDbContext == false) _ctx._affrows += affrows;
_ctx._affrows += affrows;
} }
internal void TrackToList(object list) { internal void TrackToList(object list) {
if (list == null) return; if (list == null) return;

View File

@ -8,11 +8,8 @@ namespace FreeSql {
partial class DbSet<TEntity> { partial class DbSet<TEntity> {
Task DbContextExecCommandAsync() { Task DbContextExecCommandAsync() {
if (IsNoneDbContext == false) { _dicUpdateTimes.Clear();
_dicUpdateTimes.Clear(); return _ctx.ExecCommandAsync();
return _ctx.ExecCommandAsync();
}
return Task.CompletedTask;
} }
async Task<int> DbContextBetchAddAsync(EntityState[] adds) { async Task<int> DbContextBetchAddAsync(EntityState[] adds) {
@ -59,10 +56,7 @@ namespace FreeSql {
return; return;
} }
} else { } else {
if (IsNoneDbContext) EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(data));
IncrAffrows(await OrmInsert(data).ExecuteAffrowsAsync());
else
EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(data));
} }
} }
public Task AddAsync(TEntity data) => AddPrivAsync(data, true); public Task AddAsync(TEntity data) => AddPrivAsync(data, true);
@ -94,12 +88,9 @@ namespace FreeSql {
return; return;
} }
} else { } else {
if (IsNoneDbContext) //进入队列,等待 SaveChanges 时执行
IncrAffrows(await OrmInsert(data).ExecuteAffrowsAsync()); foreach (var s in data)
else EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(s));
//进入队列,等待 SaveChanges 时执行
foreach (var s in data)
EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(s));
} }
} }
#endregion #endregion
@ -154,56 +145,6 @@ namespace FreeSql {
//等待下次对比再保存 //等待下次对比再保存
return 0; return 0;
} }
internal Task<int> UpdateAffrowsAsync(TEntity data) => UpdateRangeAffrowsAsync(new[] { data });
async internal Task<int> UpdateRangeAffrowsAsync(IEnumerable<TEntity> data) {
if (CanUpdate(data, true) == false) return 0;
if (IsNoneDbContext) {
var dataarray = data.ToArray();
var ups = new List<EntityState>();
var totalAffrows = 0;
for (var a = 0; a < dataarray.Length + 1; a++) {
var item = a < dataarray.Length ? dataarray[a] : null;
if (item != null) {
var state = CreateEntityState(item);
state.Value = item;
ups.Add(state);
}
var affrows = await DbContextBetchUpdatePrivAsync(ups.ToArray(), item == null);
if (affrows == -999) { //最后一个元素已被删除
ups.RemoveAt(ups.Count - 1);
continue;
}
if (affrows == -998 || affrows == -997) { //没有执行更新
var laststate = ups[ups.Count - 1];
ups.Clear();
if (affrows == -997) ups.Add(laststate); //保留最后一个
}
if (affrows > 0) {
totalAffrows += affrows;
var islastNotUpdated = ups.Count != affrows;
var laststate = ups[ups.Count - 1];
ups.Clear();
if (islastNotUpdated) ups.Add(laststate); //保留最后一个
}
}
IncrAffrows(totalAffrows);
return totalAffrows;
}
foreach (var item in data) {
if (_dicUpdateTimes.ContainsKey(item))
await DbContextExecCommandAsync();
_dicUpdateTimes.Add(item, 1);
var state = CreateEntityState(item);
state.OldValue = item;
EnqueueToDbContext(DbContext.ExecCommandInfoType.Update, state);
}
return 0;
}
internal Task UpdateAsync(TEntity data) => UpdateAffrowsAsync(data);
internal Task UpdateRangeAsync(IEnumerable<TEntity> data) => UpdateRangeAffrowsAsync(data);
#endregion #endregion
#region RemoveAsync #region RemoveAsync
@ -212,28 +153,6 @@ namespace FreeSql {
var affrows = await this.OrmDelete(dels.Select(a => a.Value)).ExecuteAffrowsAsync(); var affrows = await this.OrmDelete(dels.Select(a => a.Value)).ExecuteAffrowsAsync();
return Math.Max(dels.Length, affrows); return Math.Max(dels.Length, affrows);
} }
internal Task<int> RemoveAffrowsAsync(TEntity data) => RemoveRangeAffrowsAsync(new[] { data });
async internal Task<int> RemoveRangeAffrowsAsync(IEnumerable<TEntity> data) {
if (CanRemove(data, true) == false) return 0;
var dels = new List<EntityState>();
foreach (var item in data) {
var state = CreateEntityState(item);
if (_states.ContainsKey(state.Key)) _states.Remove(state.Key);
_fsql.ClearEntityPrimaryValueWithIdentityAndGuid(item);
if (IsNoneDbContext) dels.Add(state);
EnqueueToDbContext(DbContext.ExecCommandInfoType.Delete, state);
}
if (IsNoneDbContext) {
var affrows = await DbContextBetchRemoveAsync(dels.ToArray());
IncrAffrows(affrows);
return affrows;
}
return 0;
}
internal Task RemoveAsync(TEntity data) => RemoveAffrowsAsync(data);
internal Task RemoveRangeAsync(IEnumerable<TEntity> data) => RemoveRangeAffrowsAsync(data);
#endregion #endregion
} }
} }

View File

@ -7,10 +7,8 @@ namespace FreeSql {
partial class DbSet<TEntity> { partial class DbSet<TEntity> {
void DbContextExecCommand() { void DbContextExecCommand() {
if (IsNoneDbContext == false) { _dicUpdateTimes.Clear();
_dicUpdateTimes.Clear(); _ctx.ExecCommand();
_ctx.ExecCommand();
}
} }
int DbContextBetchAdd(EntityState[] adds) { int DbContextBetchAdd(EntityState[] adds) {
@ -56,12 +54,8 @@ namespace FreeSql {
} }
return; return;
} }
} else { } else
if (IsNoneDbContext) EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(data));
IncrAffrows(OrmInsert(data).ExecuteAffrows());
else
EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(data));
}
} }
public void Add(TEntity data) => AddPriv(data, true); public void Add(TEntity data) => AddPriv(data, true);
public void AddRange(IEnumerable<TEntity> data) { public void AddRange(IEnumerable<TEntity> data) {
@ -92,12 +86,9 @@ namespace FreeSql {
return; return;
} }
} else { } else {
if (IsNoneDbContext) //进入队列,等待 SaveChanges 时执行
IncrAffrows(OrmInsert(data).ExecuteAffrows()); foreach (var s in data)
else EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(s));
//进入队列,等待 SaveChanges 时执行
foreach (var s in data)
EnqueueToDbContext(DbContext.ExecCommandInfoType.Insert, CreateEntityState(s));
} }
} }
#endregion #endregion
@ -154,42 +145,9 @@ namespace FreeSql {
} }
Dictionary<TEntity, byte> _dicUpdateTimes = new Dictionary<TEntity, byte>(); Dictionary<TEntity, byte> _dicUpdateTimes = new Dictionary<TEntity, byte>();
internal int UpdateAffrows(TEntity data) => UpdateRangeAffrows(new[] { data }); public void Update(TEntity data) => UpdateRange(new[] { data });
internal int UpdateRangeAffrows(IEnumerable<TEntity> data) { public void UpdateRange(IEnumerable<TEntity> data) {
if (CanUpdate(data, true) == false) return 0; if (CanUpdate(data, true) == false) return;
if (IsNoneDbContext) {
var dataarray = data.ToArray();
var ups = new List<EntityState>();
var totalAffrows = 0;
for (var a = 0; a < dataarray.Length + 1; a++) {
var item = a < dataarray.Length ? dataarray[a] : null;
if (item != null) {
var state = CreateEntityState(item);
state.Value = item;
ups.Add(state);
}
var affrows = DbContextBetchUpdatePriv(ups.ToArray(), item == null);
if (affrows == -999) { //最后一个元素已被删除
ups.RemoveAt(ups.Count - 1);
continue;
}
if (affrows == -998 || affrows == -997) { //没有执行更新
var laststate = ups[ups.Count - 1];
ups.Clear();
if (affrows == -997) ups.Add(laststate); //保留最后一个
}
if (affrows > 0) {
totalAffrows += affrows;
var islastNotUpdated = ups.Count != affrows;
var laststate = ups[ups.Count - 1];
ups.Clear();
if (islastNotUpdated) ups.Add(laststate); //保留最后一个
}
}
IncrAffrows(totalAffrows);
return totalAffrows;
}
foreach (var item in data) { foreach (var item in data) {
if (_dicUpdateTimes.ContainsKey(item)) if (_dicUpdateTimes.ContainsKey(item))
DbContextExecCommand(); DbContextExecCommand();
@ -199,10 +157,7 @@ namespace FreeSql {
state.OldValue = item; state.OldValue = item;
EnqueueToDbContext(DbContext.ExecCommandInfoType.Update, state); EnqueueToDbContext(DbContext.ExecCommandInfoType.Update, state);
} }
return 0;
} }
public void Update(TEntity data) => UpdateAffrows(data);
public void UpdateRange(IEnumerable<TEntity> data) => UpdateRangeAffrows(data);
#endregion #endregion
#region Remove #region Remove
@ -212,27 +167,17 @@ namespace FreeSql {
return Math.Max(dels.Length, affrows); return Math.Max(dels.Length, affrows);
} }
internal int RemoveAffrows(TEntity data) => RemoveRangeAffrows(new[] { data }); public void Remove(TEntity data) => RemoveRange(new[] { data });
internal int RemoveRangeAffrows(IEnumerable<TEntity> data) { public void RemoveRange(IEnumerable<TEntity> data) {
if (CanRemove(data, true) == false) return 0; if (CanRemove(data, true) == false) return;
var dels = new List<EntityState>();
foreach (var item in data) { foreach (var item in data) {
var state = CreateEntityState(item); var state = CreateEntityState(item);
if (_states.ContainsKey(state.Key)) _states.Remove(state.Key); if (_states.ContainsKey(state.Key)) _states.Remove(state.Key);
_fsql.ClearEntityPrimaryValueWithIdentityAndGuid(item); _fsql.ClearEntityPrimaryValueWithIdentityAndGuid(item);
if (IsNoneDbContext) dels.Add(state);
EnqueueToDbContext(DbContext.ExecCommandInfoType.Delete, state); EnqueueToDbContext(DbContext.ExecCommandInfoType.Delete, state);
} }
if (IsNoneDbContext) {
var affrows = DbContextBetchRemove(dels.ToArray());
IncrAffrows(affrows);
return affrows;
}
return 0;
} }
public void Remove(TEntity data) => RemoveAffrows(data);
public void RemoveRange(IEnumerable<TEntity> data) => RemoveRangeAffrows(data);
#endregion #endregion
} }
} }

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSql {
internal class RepositoryDbContext<TEntity> : DbContext where TEntity : class {
protected BaseRepository<TEntity> _repos;
public RepositoryDbContext(IFreeSql orm, BaseRepository<TEntity> repos) : base() {
_orm = orm;
_repos = repos;
_isUseUnitOfWork = false;
}
public override object Set(Type entityType) {
if (_dicSet.ContainsKey(entityType)) return _dicSet[entityType];
var sd = Activator.CreateInstance(typeof(RepositoryDbSet<>).MakeGenericType(entityType), _repos);
_dicSet.Add(entityType, sd);
return sd;
}
RepositoryDbSet<TEntity> _dbSet;
public RepositoryDbSet<TEntity> DbSet => _dbSet ?? (_dbSet = Set<TEntity>() as RepositoryDbSet<TEntity>);
}
}

View File

@ -9,8 +9,9 @@ namespace FreeSql {
protected BaseRepository<TEntity> _repos; protected BaseRepository<TEntity> _repos;
public RepositoryDbSet(BaseRepository<TEntity> repos) { public RepositoryDbSet(BaseRepository<TEntity> repos) {
_ctx = repos._db;
_fsql = repos._fsql; _fsql = repos._fsql;
_uow = repos._uow; _uow = repos.UnitOfWork;
_repos = repos; _repos = repos;
} }

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql {
public interface IRepositoryUnitOfWork : IUnitOfWork {
/// <summary>
/// 在工作单元内创建默认仓库类,工作单元下的仓储操作具有事务特点
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="filter">数据过滤 + 验证</param>
/// <returns></returns>
DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class;
/// <summary>
/// 在工作单元内创建仓库类,工作单元下的仓储操作具有事务特点
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="filter">数据过滤 + 验证</param>
/// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
/// <returns></returns>
GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class;
}
class RepositoryUnitOfWork : UnitOfWork, IRepositoryUnitOfWork {
public RepositoryUnitOfWork(IFreeSql fsql) : base(fsql) {
}
public GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class {
var repos = new GuidRepository<TEntity>(_fsql, filter, asTable);
repos.UnitOfWork = this;
return repos;
}
public DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class {
var repos = new DefaultRepository<TEntity, TKey>(_fsql, filter);
repos.UnitOfWork = this;
return repos;
}
}
}

View File

@ -22,7 +22,7 @@ public static class FreeSqlRepositoryExtenssions {
} }
/// <summary> /// <summary>
/// 返回仓库类,适用 Insert 方法无须返回插入的数据 /// 返回仓库类
/// </summary> /// </summary>
/// <typeparam name="TEntity"></typeparam> /// <typeparam name="TEntity"></typeparam>
/// <param name="that"></param> /// <param name="that"></param>

View File

@ -11,9 +11,7 @@ namespace FreeSql {
where TEntity : class { where TEntity : class {
internal IFreeSql _fsql; internal IFreeSql _fsql;
internal UnitOfWork _uow; internal RepositoryDbContext<TEntity> _db;
RepositoryDbSet<TEntity> _setPriv;
internal RepositoryDbSet<TEntity> _set => _setPriv ?? (_setPriv = new RepositoryDbSet<TEntity>(this));
public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>(); public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>();
Func<string, string> _asTableVal; Func<string, string> _asTableVal;
protected Func<string, string> AsTable { protected Func<string, string> AsTable {
@ -32,45 +30,89 @@ namespace FreeSql {
DataFilterUtil.SetRepositoryDataFilter(this, null); DataFilterUtil.SetRepositoryDataFilter(this, null);
DataFilter.Apply("", filter); DataFilter.Apply("", filter);
AsTable = asTable; AsTable = asTable;
_db = new RepositoryDbContext<TEntity>(_fsql, this);
} }
public Type EntityType => _set._entityTypeInternal; ~BaseRepository() {
public IUpdate<TEntity> UpdateDiy => _set.OrmUpdateInternal(null); this.Dispose();
}
bool _isdisposed = false;
public void Dispose() {
if (_isdisposed) return;
try {
_db.Dispose();
this.DataFilter.Dispose();
} finally {
_isdisposed = true;
GC.SuppressFinalize(this);
}
}
public IUnitOfWork UnitOfWork { get; set; }
public Type EntityType => _db.DbSet._entityTypeInternal;
public IUpdate<TEntity> UpdateDiy => _db.DbSet.OrmUpdateInternal(null);
public ISelect<TEntity> Select => _set.OrmSelectInternal(null); public ISelect<TEntity> Select => _db.DbSet.OrmSelectInternal(null);
public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => _set.OrmSelectInternal(null).Where(exp); public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => _db.DbSet.OrmSelectInternal(null).Where(exp);
public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => _set.OrmSelectInternal(null).WhereIf(condition, exp); public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => _db.DbSet.OrmSelectInternal(null).WhereIf(condition, exp);
public int Delete(Expression<Func<TEntity, bool>> predicate) => _set.OrmDeleteInternal(null).Where(predicate).ExecuteAffrows(); public int Delete(Expression<Func<TEntity, bool>> predicate) => _db.DbSet.OrmDeleteInternal(null).Where(predicate).ExecuteAffrows();
public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate) => _set.OrmDeleteInternal(null).Where(predicate).ExecuteAffrowsAsync(); public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate) => _db.DbSet.OrmDeleteInternal(null).Where(predicate).ExecuteAffrowsAsync();
public int Delete(TEntity entity) => _set.RemoveAffrows(entity); public int Delete(TEntity entity) {
public Task<int> DeleteAsync(TEntity entity) => _set.RemoveAffrowsAsync(entity); _db.DbSet.Remove(entity);
public int Delete(IEnumerable<TEntity> entitys) => _set.RemoveRangeAffrows(entitys); return _db.SaveChanges();
public Task<int> DeleteAsync(IEnumerable<TEntity> entitys) => _set.RemoveRangeAffrowsAsync(entitys); }
public Task<int> DeleteAsync(TEntity entity) {
_db.DbSet.Remove(entity);
return _db.SaveChangesAsync();
}
public int Delete(IEnumerable<TEntity> entitys) {
_db.DbSet.RemoveRange(entitys);
return _db.SaveChanges();
}
public Task<int> DeleteAsync(IEnumerable<TEntity> entitys) {
_db.DbSet.RemoveRange(entitys);
return _db.SaveChangesAsync();
}
public virtual TEntity Insert(TEntity entity) { public virtual TEntity Insert(TEntity entity) {
_set.Add(entity); _db.DbSet.Add(entity);
_db.SaveChanges();
return entity;
}
async public virtual Task<TEntity> InsertAsync(TEntity entity) {
await _db.DbSet.AddAsync(entity);
_db.SaveChanges();
return entity; return entity;
} }
public virtual List<TEntity> Insert(IEnumerable<TEntity> entitys) { public virtual List<TEntity> Insert(IEnumerable<TEntity> entitys) {
_set.AddRange(entitys); _db.DbSet.AddRange(entitys);
_db.SaveChanges();
return entitys.ToList(); return entitys.ToList();
} }
async public virtual Task<TEntity> InsertAsync(TEntity entity) {
await _set.AddAsync(entity);
return entity;
}
async public virtual Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys) { async public virtual Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys) {
await _set.AddRangeAsync(entitys); await _db.DbSet.AddRangeAsync(entitys);
await _db.SaveChangesAsync();
return entitys.ToList(); return entitys.ToList();
} }
public int Update(TEntity entity) => _set.UpdateAffrows(entity); public int Update(TEntity entity) {
public Task<int> UpdateAsync(TEntity entity) => _set.UpdateAffrowsAsync(entity); _db.DbSet.Update(entity);
public int Update(IEnumerable<TEntity> entitys) => _set.UpdateRangeAffrows(entitys); return _db.SaveChanges();
public Task<int> UpdateAsync(IEnumerable<TEntity> entitys) => _set.UpdateRangeAffrowsAsync(entitys); }
public Task<int> UpdateAsync(TEntity entity) {
_db.DbSet.Update(entity);
return _db.SaveChangesAsync();
}
public int Update(IEnumerable<TEntity> entitys) {
_db.DbSet.UpdateRange(entitys);
return _db.SaveChanges();
}
public Task<int> UpdateAsync(IEnumerable<TEntity> entitys) {
_db.DbSet.UpdateRange(entitys);
return _db.SaveChangesAsync();
}
} }
public abstract class BaseRepository<TEntity, TKey> : BaseRepository<TEntity>, IRepository<TEntity, TKey> public abstract class BaseRepository<TEntity, TKey> : BaseRepository<TEntity>, IRepository<TEntity, TKey>
@ -81,17 +123,19 @@ namespace FreeSql {
public int Delete(TKey id) { public int Delete(TKey id) {
var stateKey = string.Concat(id); var stateKey = string.Concat(id);
if (_set._statesInternal.ContainsKey(stateKey)) _set._statesInternal.Remove(stateKey); if (_db.DbSet._statesInternal.ContainsKey(stateKey))
return _set.OrmDeleteInternal(id).ExecuteAffrows(); _db.DbSet._statesInternal.Remove(stateKey);
return _db.DbSet.OrmDeleteInternal(id).ExecuteAffrows();
} }
public Task<int> DeleteAsync(TKey id) { public Task<int> DeleteAsync(TKey id) {
var stateKey = string.Concat(id); var stateKey = string.Concat(id);
if (_set._statesInternal.ContainsKey(stateKey)) _set._statesInternal.Remove(stateKey); if (_db.DbSet._statesInternal.ContainsKey(stateKey))
return _set.OrmDeleteInternal(id).ExecuteAffrowsAsync(); _db.DbSet._statesInternal.Remove(stateKey);
return _db.DbSet.OrmDeleteInternal(id).ExecuteAffrowsAsync();
} }
public TEntity Find(TKey id) => _set.OrmSelectInternal(id).ToOne(); public TEntity Find(TKey id) => _db.DbSet.OrmSelectInternal(id).ToOne();
public Task<TEntity> FindAsync(TKey id) => _set.OrmSelectInternal(id).ToOneAsync(); public Task<TEntity> FindAsync(TKey id) => _db.DbSet.OrmSelectInternal(id).ToOneAsync();
public TEntity Get(TKey id) => Find(id); public TEntity Get(TKey id) => Find(id);
public Task<TEntity> GetAsync(TKey id) => FindAsync(id); public Task<TEntity> GetAsync(TKey id) => FindAsync(id);

View File

@ -4,8 +4,9 @@ using System.Threading.Tasks;
namespace FreeSql { namespace FreeSql {
public interface IRepository { public interface IRepository : IDisposable {
Type EntityType { get; } Type EntityType { get; }
IUnitOfWork UnitOfWork { get; set; }
} }
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity> public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql {
class RepositoryUnitOfWork : UnitOfWork, IRepositoryUnitOfWork {
public RepositoryUnitOfWork(IFreeSql fsql) : base(fsql) {
}
public GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class {
var repos = new GuidRepository<TEntity>(_fsql, filter, asTable);
repos._uow = this;
return repos;
}
public DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class {
var repos = new DefaultRepository<TEntity, TKey>(_fsql, filter);
repos._uow = this;
return repos;
}
}
}

View File

@ -1,34 +1,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Text; using System.Text;
namespace FreeSql { namespace FreeSql {
public interface IUnitOfWork : IDisposable { public interface IUnitOfWork : IDisposable {
DbTransaction GetOrBeginTransaction(bool isCreate = true);
void Commit(); void Commit();
void Rollback(); void Rollback();
} }
public interface IRepositoryUnitOfWork : IUnitOfWork {
/// <summary>
/// 在工作单元内创建默认仓库类,工作单元下的仓储操作具有事务特点
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="filter">数据过滤 + 验证</param>
/// <returns></returns>
DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class;
/// <summary>
/// 在工作单元内创建仓库类,适用 Insert 方法无须返回插入的数据,工作单元下的仓储操作具有事务特点
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="filter">数据过滤 + 验证</param>
/// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
/// <returns></returns>
GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class;
}
} }

View File

@ -21,7 +21,7 @@ namespace FreeSql {
_tran = null; _tran = null;
_conn = null; _conn = null;
} }
internal DbTransaction GetOrBeginTransaction(bool isCreate = true) { public DbTransaction GetOrBeginTransaction(bool isCreate = true) {
if (_tran != null) return _tran; if (_tran != null) return _tran;
if (isCreate == false) return null; if (isCreate == false) return null;