diff --git a/Examples/base_entity/BaseEntity.cs b/Examples/base_entity/BaseEntity.cs index 018c7d58..84df35b2 100644 --- a/Examples/base_entity/BaseEntity.cs +++ b/Examples/base_entity/BaseEntity.cs @@ -2,8 +2,10 @@ using FreeSql.DataAnnotations; using Newtonsoft.Json; using System; +using System.Data; using System.Diagnostics; using System.Linq.Expressions; +using System.Threading.Tasks; [Table(DisableSyncStructure = true)] public abstract class BaseEntity @@ -13,7 +15,7 @@ public abstract class BaseEntity var orm = new FreeSqlBuilder() .UseAutoSyncStructure(true) .UseNoneCommandParameter(true) - .UseConnectionString(DataType.Sqlite, "data source=test.db;max pool size=2") + .UseConnectionString(DataType.Sqlite, "data source=test.db;max pool size=5") //.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=2") //.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2") //.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=2") @@ -36,71 +38,108 @@ public abstract class BaseEntity /// 逻辑删除 /// public bool IsDeleted { get; set; } + + /// + /// 开启工作单元事务 + /// + /// + /// + public static IUnitOfWork Begin() => Begin(null); + public static IUnitOfWork Begin(IsolationLevel? level) + { + var uow = new BaseEntityUnitOfWork(Orm); + uow.IsolationLevel = level; + return uow; + } + protected static IUnitOfWork CurrentUow => BaseEntityUnitOfWork._asyncUow.Value; } [Table(DisableSyncStructure = true)] public abstract class BaseEntity : BaseEntity where TEntity : class { - public static ISelect Select => Orm.Select().WhereCascade(a => (a as BaseEntity).IsDeleted == false); + public static ISelect Select => Orm.Select() + .WithTransaction(CurrentUow?.GetOrBeginTransaction(false)) + .WhereCascade(a => (a as BaseEntity).IsDeleted == false); public static ISelect Where(Expression> exp) => Select.Where(exp); public static ISelect WhereIf(bool condition, Expression> exp) => Select.WhereIf(condition, exp); [JsonIgnore] protected IBaseRepository Repository { get; set; } - bool UpdateIsDeleted(bool value) + async Task UpdateIsDeleted(bool value) { if (this.Repository == null) - return Orm.Update(this as TEntity).Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1; + return await Orm.Update(this as TEntity) + .WithTransaction(CurrentUow?.GetOrBeginTransaction()) + .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrowsAsync() == 1; + this.IsDeleted = value; - return this.Repository.Update(this as TEntity) == 1; + this.Repository.UnitOfWork = CurrentUow; + return await this.Repository.UpdateAsync(this as TEntity) == 1; } /// /// 删除数据 /// /// - public virtual bool Delete() => this.UpdateIsDeleted(true); + public virtual Task Delete() => this.UpdateIsDeleted(true); /// /// 恢复删除的数据 /// /// - public virtual bool Restore() => this.UpdateIsDeleted(false); + public virtual Task Restore() => this.UpdateIsDeleted(false); /// /// 附加实体,在更新数据时,只更新变化的部分 /// - public void Attach() + public TEntity Attach() { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.Attach(this as TEntity); + if (this.Repository == null) + this.Repository = Orm.GetRepository(); + + var item = this as TEntity; + this.Repository.Attach(item); + return item; } /// /// 更新数据 /// /// - public virtual bool Update() + async public virtual Task Update() { + this.UpdateTime = DateTime.Now; if (this.Repository == null) - return Orm.Update().SetSource(this as TEntity).ExecuteAffrows() == 1; - return this.Repository.Update(this as TEntity) == 1; + return await Orm.Update() + .WithTransaction(CurrentUow?.GetOrBeginTransaction()) + .SetSource(this as TEntity).ExecuteAffrowsAsync() == 1; + + this.Repository.UnitOfWork = CurrentUow; + return await this.Repository.UpdateAsync(this as TEntity) == 1; } /// /// 插入数据 /// - public virtual void Insert() + async public virtual Task Insert() { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.Insert(this as TEntity); + this.CreateTime = DateTime.Now; + if (this.Repository == null) + this.Repository = Orm.GetRepository(); + + this.Repository.UnitOfWork = CurrentUow; + await this.Repository.InsertAsync(this as TEntity); } /// /// 更新或插入 /// /// - public virtual void Save() + async public virtual Task Save() { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.InsertOrUpdate(this as TEntity); + this.UpdateTime = DateTime.Now; + if (this.Repository == null) + this.Repository = Orm.GetRepository(); + + this.Repository.UnitOfWork = CurrentUow; + await this.Repository.InsertOrUpdateAsync(this as TEntity); } } @@ -125,43 +164,10 @@ public abstract class BaseEntity : BaseEntity where TEnt /// /// /// - public static TEntity Find(TKey id) + async public static Task Find(TKey id) { - var item = Select.WhereDynamic(id).First(); + var item = await Select.WhereDynamic(id).FirstAsync(); (item as BaseEntity)?.Attach(); return item; } -} - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity : BaseEntity where TEntity : class -{ - - /// - /// 主键1 - /// - [Column(IsPrimary = true)] - public virtual TKey1 PkId1 { get; set; } - /// - /// 主键2 - /// - [Column(IsPrimary = true)] - public virtual TKey2 PkId2 { get; set; } - - /// - /// 根据主键值获取数据 - /// - /// 主键1 - /// 主键2 - /// - public static TEntity Find(TKey1 pkid1, TKey1 pkid2) - { - var item = Select.WhereDynamic(new - { - PkId1 = pkid1, - PkId2 = pkid2 - }).First(); - (item as BaseEntity).Attach(); - return item; - } } \ No newline at end of file diff --git a/Examples/base_entity/BaseEntityUnitOfWork.cs b/Examples/base_entity/BaseEntityUnitOfWork.cs new file mode 100644 index 00000000..0199b2c1 --- /dev/null +++ b/Examples/base_entity/BaseEntityUnitOfWork.cs @@ -0,0 +1,124 @@ +using FreeSql; +using SafeObjectPool; +using System; +using System.Data; +using System.Data.Common; +using System.Threading; + +class BaseEntityUnitOfWork : IUnitOfWork +{ + internal readonly static AsyncLocal _asyncUow = new AsyncLocal(); + + protected IFreeSql _fsql; + protected Object _conn; + protected DbTransaction _tran; + + public BaseEntityUnitOfWork(IFreeSql fsql) + { + _fsql = fsql; + _asyncUow.Value = this; + } + + void ReturnObject() + { + _fsql.Ado.MasterPool.Return(_conn); + _tran = null; + _conn = null; + _asyncUow.Value = null; + } + + + /// + /// 是否启用工作单元 + /// + public bool Enable { get; private set; } = true; + + /// + /// 禁用工作单元 + /// + /// + /// 若已开启事务(已有Insert/Update/Delete操作),调用此方法将发生异常,建议在执行逻辑前调用 + /// + public void Close() + { + if (_tran != null) + throw new Exception("已开启事务,不能禁用工作单元"); + + Enable = false; + } + + public void Open() => + Enable = true; + + public IsolationLevel? IsolationLevel { get; set; } + + public DbTransaction GetOrBeginTransaction(bool isCreate = true) + { + + if (_tran != null) return _tran; + if (isCreate == false) return null; + if (!Enable) return null; + if (_conn != null) _fsql.Ado.MasterPool.Return(_conn); + + _conn = _fsql.Ado.MasterPool.Get(); + try + { + _tran = IsolationLevel == null ? + _conn.Value.BeginTransaction() : + _conn.Value.BeginTransaction(IsolationLevel.Value); + } + catch + { + ReturnObject(); + throw; + } + return _tran; + } + + public void Commit() + { + if (_tran != null) + { + try + { + _tran.Commit(); + } + finally + { + ReturnObject(); + } + } + } + public void Rollback() + { + if (_tran != null) + { + try + { + _tran.Rollback(); + } + finally + { + ReturnObject(); + } + } + } + ~BaseEntityUnitOfWork() + { + this.Dispose(); + } + bool _isdisposed = false; + public void Dispose() + { + if (_isdisposed) return; + _isdisposed = true; + try + { + this.Rollback(); + } + finally + { + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/Examples/base_entity/Entities/User.cs b/Examples/base_entity/Entities/User.cs index a062d1a0..7db6ab8c 100644 --- a/Examples/base_entity/Entities/User.cs +++ b/Examples/base_entity/Entities/User.cs @@ -10,8 +10,6 @@ public class UserGroup : BaseEntity public string GroupName { get; set; } public List User1s { get; set; } - - public List User2s { get; set; } } public class Role : BaseEntity @@ -54,38 +52,3 @@ public class User1 : BaseEntity /// public string Description { get; set; } } - -public class User2 : BaseEntity -{ - static User2() - { - User2.Orm.CodeFirst.ConfigEntity(t => - { - t.Property(a => a.PkId1).Name("UserId"); - t.Property(a => a.PkId2).Name("Index"); - }); - } - - public int GroupId { get; set; } - public UserGroup Group { get; set; } - - /// - /// 登陆名 - /// - public string Username { get; set; } - - /// - /// 昵称 - /// - public string Nickname { get; set; } - - /// - /// 头像 - /// - public string Avatar { get; set; } - - /// - /// 描述 - /// - public string Description { get; set; } -} \ No newline at end of file diff --git a/Examples/base_entity/Program.cs b/Examples/base_entity/Program.cs index 7de6d4d4..c09610de 100644 --- a/Examples/base_entity/Program.cs +++ b/Examples/base_entity/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace base_entity { @@ -6,74 +7,70 @@ namespace base_entity { static void Main(string[] args) { - var ug1 = new UserGroup(); - ug1.GroupName = "分组一"; - ug1.Insert(); + Task.Run(async () => + { + using (var uow = BaseEntity.Begin()) + { + var itt = await UserGroup.Find(1); + } - var ug2 = new UserGroup(); - ug2.GroupName = "分组二"; - ug2.Insert(); + var ug1 = new UserGroup(); + ug1.GroupName = "分组一"; + await ug1.Insert(); - var u1 = new User1(); - var u2 = new User2(); + var ug2 = new UserGroup(); + ug2.GroupName = "分组二"; + await ug2.Insert(); - u1.GroupId = ug1.Id; - u1.Save(); + var u1 = new User1(); - u2.GroupId = ug2.Id; - u2.Save(); + u1.GroupId = ug1.Id; + await u1.Save(); - u1.Delete(); - u1.Restore(); + await u1.Delete(); + await u1.Restore(); - u1.Nickname = "x1"; - u1.Update(); + u1.Nickname = "x1"; + await u1.Update(); - u2.Delete(); - u2.Restore(); + var u11 = await User1.Find(u1.Id); + u11.Description = "备注"; + await u11.Save(); - u2.Username = "x2"; - u2.Update(); + await u11.Delete(); - var u11 = User1.Find(u1.Id); - u11.Description = "备注"; - u11.Save(); + var u11null = User1.Find(u1.Id); - u11.Delete(); + var u11s = User1.Where(a => a.Group.Id == ug1.Id).Limit(10).ToList(); - var u11null = User1.Find(u1.Id); + var u11s2 = User1.Select.LeftJoin((a, b) => a.GroupId == b.Id).Limit(10).ToList(); - var u11s = User1.Where(a => a.Group.Id == ug1.Id).Limit(10).ToList(); - var u22s = User2.Where(a => a.Group.Id == ug2.Id).Limit(10).ToList(); + var ug1s = UserGroup.Select + .IncludeMany(a => a.User1s) + .Limit(10).ToList(); - var u11s2 = User1.Select.LeftJoin((a, b) => a.GroupId == b.Id).Limit(10).ToList(); - var u22s2 = User2.Select.LeftJoin((a, b) => a.GroupId == b.Id).Limit(10).ToList(); + var ug1s2 = UserGroup.Select.Where(a => a.User1s.AsSelect().Any(b => b.Nickname == "x1")).Limit(10).ToList(); - var ug1s = UserGroup.Select - .IncludeMany(a => a.User1s) - .IncludeMany(a => a.User2s) - .Limit(10).ToList(); + var r1 = new Role(); + r1.Id = "管理员"; + await r1.Save(); - var ug1s2 = UserGroup.Select.Where(a => a.User1s.AsSelect().Any(b => b.Nickname == "x1")).Limit(10).ToList(); + var r2 = new Role(); + r2.Id = "超级会员"; + await r2.Save(); - var r1 = new Role(); - r1.Id = "管理员"; - r1.Save(); + var ru1 = new RoleUser1(); + ru1.User1Id = u1.Id; + ru1.RoleId = r1.Id; + await ru1.Save(); - var r2 = new Role(); - r2.Id = "超级会员"; - r2.Save(); + ru1.RoleId = r2.Id; + await ru1.Save(); - var ru1 = new RoleUser1(); - ru1.User1Id = u1.Id; - ru1.RoleId = r1.Id; - ru1.Save(); + var u1roles = User1.Select.IncludeMany(a => a.Roles).ToList(); + var u1roles2 = User1.Select.Where(a => a.Roles.AsSelect().Any(b => b.Id == "xx")).ToList(); - ru1.RoleId = r2.Id; - ru1.Save(); - - var u1roles = User1.Select.IncludeMany(a => a.Roles).ToList(); - var u1roles2 = User1.Select.Where(a => a.Roles.AsSelect().Any(b => b.Id == "xx")).ToList(); + }).Wait(); Console.WriteLine("按任意键结束。。。"); Console.ReadKey();