From 6d5575def19a6ebb7e54652f10b6312e8cafaf01 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 8 May 2020 14:49:24 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E8=B0=83=E6=95=B4=20BaseEntity=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=20BaseTreeEntity=E3=80=81Tenant=20=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=EF=BC=8C=E6=94=B9=E5=8F=98=E4=BA=8B=E5=8A=A1=E4=B9=A0?= =?UTF-8?q?=E6=83=AF=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Examples/base_entity/Program.cs | 16 +- .../BaseEntity.cs | 33 ++-- .../BaseEntityAsync.cs | 34 ++-- .../BaseEntityReadOnly.cs | 105 +++-------- .../BaseEntityTree.cs | 168 ------------------ .../FreeSql.Extensions.BaseEntity.csproj | 10 +- .../FreeSql.Extensions.BaseEntity.xml | 75 ++------ .../Net40/BaseEntity.cs | 122 ------------- .../Net40/BaseEntityReadOnly.cs | 130 -------------- .../FreeSql.Extensions.BaseEntity/readme.md | 36 +++- FreeSql.Tests.VB/UnitTest1.vb | 2 +- .../FreeSql.Tests.DbContext/UnitTest1.cs | 2 +- 12 files changed, 128 insertions(+), 605 deletions(-) delete mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs delete mode 100644 Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntity.cs delete mode 100644 Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntityReadOnly.cs diff --git a/Examples/base_entity/Program.cs b/Examples/base_entity/Program.cs index c1440834..256a8653 100644 --- a/Examples/base_entity/Program.cs +++ b/Examples/base_entity/Program.cs @@ -37,6 +37,8 @@ namespace base_entity public string title { get; set; } } + static AsyncLocal _asyncUow = new AsyncLocal(); + static void Main(string[] args) { @@ -73,7 +75,7 @@ namespace base_entity .UseMonitorCommand(cmd => Console.Write(cmd.CommandText)) .UseLazyLoading(true) .Build(); - BaseEntity.Initialization(fsql); + BaseEntity.Initialization(fsql, () => _asyncUow.Value); #endregion var test01 = EMSServerModel.Model.User.Select.IncludeMany(a => a.Roles).ToList(); @@ -144,9 +146,17 @@ namespace base_entity Task.Run(async () => { - using (var uow = BaseEntity.Begin()) + using (var uow = BaseEntity.Orm.CreateUnitOfWork()) { - var id = (await new User1().SaveAsync()).Id; + _asyncUow.Value = uow; + try + { + var id = (await new User1().SaveAsync()).Id; + } + finally + { + _asyncUow.Value = null; + } uow.Commit(); } diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs index a3064ad9..40382f84 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs @@ -1,6 +1,4 @@ -#if netcore - -using FreeSql; +using FreeSql; using FreeSql.DataAnnotations; using System; using System.Data; @@ -34,6 +32,8 @@ namespace FreeSql [Column(Position = 1)] public virtual TKey Id { get; set; } +#if net40 +#else /// /// 根据主键值获取数据 /// @@ -45,6 +45,7 @@ namespace FreeSql (item as BaseEntity)?.Attach(); return item; } +#endif /// /// 根据主键值获取数据 @@ -70,12 +71,11 @@ namespace FreeSql { if (this.Repository == null) return Orm.Update(this as TEntity) - .WithTransaction(CurrentUnitOfWork?.GetOrBeginTransaction()) + .WithTransaction(_resolveUow?.Invoke()?.GetOrBeginTransaction()) .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1; - this.SetTenantId(); this.IsDeleted = value; - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.Update(this as TEntity) == 1; } /// @@ -88,8 +88,8 @@ namespace FreeSql if (physicalDelete == false) return this.UpdateIsDeleted(true); if (this.Repository == null) return Orm.Delete(this as TEntity).ExecuteAffrows() == 1; - //this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.Delete(this as TEntity) == 1; } /// @@ -107,11 +107,10 @@ namespace FreeSql this.UpdateTime = DateTime.Now; if (this.Repository == null) return Orm.Update() - .WithTransaction(CurrentUnitOfWork?.GetOrBeginTransaction()) + .WithTransaction(_resolveUow?.Invoke()?.GetOrBeginTransaction()) .SetSource(this as TEntity).ExecuteAffrows() == 1; - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.Update(this as TEntity) == 1; } /// @@ -123,8 +122,7 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.Insert(this as TEntity); } @@ -138,8 +136,7 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.InsertOrUpdate(this as TEntity); } @@ -152,10 +149,8 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); this.Repository.SaveMany(this as TEntity, navigatePropertyName); } } -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs index 8b0e5ed2..ca589470 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs @@ -1,5 +1,4 @@ -#if netcore - + using FreeSql; using FreeSql.DataAnnotations; using System; @@ -27,8 +26,11 @@ namespace FreeSql /// /// 主键 /// + [Column(Position = 1)] public virtual TKey Id { get; set; } +#if net40 +#else /// /// 根据主键值获取数据 /// @@ -40,6 +42,8 @@ namespace FreeSql (item as BaseEntity)?.Attach(); return item; } +#endif + } /// @@ -49,15 +53,17 @@ namespace FreeSql [Table(DisableSyncStructure = true)] public abstract class BaseEntityAsync : BaseEntityReadOnly where TEntity : class { +#if net40 +#else async Task UpdateIsDeletedAsync(bool value) { if (this.Repository == null) return await Orm.Update(this as TEntity) - .WithTransaction(CurrentUnitOfWork?.GetOrBeginTransaction()) + .WithTransaction(_resolveUow?.Invoke()?.GetOrBeginTransaction()) .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrowsAsync() == 1; this.IsDeleted = value; - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return await this.Repository.UpdateAsync(this as TEntity) == 1; } /// @@ -70,8 +76,8 @@ namespace FreeSql if (physicalDelete == false) return await this.UpdateIsDeletedAsync(true); if (this.Repository == null) return await Orm.Delete(this as TEntity).ExecuteAffrowsAsync() == 1; - //this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return await this.Repository.DeleteAsync(this as TEntity) == 1; } /// @@ -89,11 +95,10 @@ namespace FreeSql this.UpdateTime = DateTime.Now; if (this.Repository == null) return await Orm.Update() - .WithTransaction(CurrentUnitOfWork?.GetOrBeginTransaction()) + .WithTransaction(_resolveUow?.Invoke()?.GetOrBeginTransaction()) .SetSource(this as TEntity).ExecuteAffrowsAsync() == 1; - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return await this.Repository.UpdateAsync(this as TEntity) == 1; } /// @@ -105,8 +110,7 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.InsertAsync(this as TEntity); } @@ -120,8 +124,7 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.SetTenantId(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.InsertOrUpdateAsync(this as TEntity); } @@ -134,10 +137,9 @@ namespace FreeSql if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.UnitOfWork = CurrentUnitOfWork; + this.Repository.UnitOfWork = _resolveUow?.Invoke(); return this.Repository.SaveManyAsync(this as TEntity, navigatePropertyName); } +#endif } } - -#endif \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs index d4efcbff..b3dd1c8a 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs @@ -1,11 +1,10 @@ -#if netcore - + using FreeSql.DataAnnotations; using System; using System.Collections; -using System.Collections.Generic; using System.Collections.Concurrent; -using System.Data; +using System.Collections.Generic; +using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; @@ -27,6 +26,7 @@ namespace FreeSql .UseAutoSyncStructure(true) .UseConnectionString(DataType.Sqlite, ""data source=test.db;max pool size=5"") .Build());"); + internal static Func _resolveUow; /// /// 初始化BaseEntity @@ -39,7 +39,8 @@ namespace FreeSql /// .Build()); /// /// IFreeSql orm 对象 - public static void Initialization(IFreeSql fsql) + /// 工作单元(事务)委托,如果不使用事务请传 null解释:由于AsyncLocal平台兼容不好,所以交给外部管理 + public static void Initialization(IFreeSql fsql, Func resolveUow) { _ormPriv = fsql; _ormPriv.Aop.CurdBefore += (s, e) => Trace.WriteLine($"\r\n线程{Thread.CurrentThread.ManagedThreadId}: {e.Sql}\r\n"); @@ -51,6 +52,7 @@ namespace FreeSql _ormPriv.CodeFirst.ConfigEntity(cei.EntityType, cei.Fluent); } } + _resolveUow = resolveUow; } class ConfigEntityInfo @@ -75,72 +77,25 @@ namespace FreeSql /// 创建时间 /// [Column(Position = -4)] - public DateTime CreateTime { get; set; } = DateTime.Now; + public virtual DateTime CreateTime { get; set; } = DateTime.Now; /// /// 更新时间 /// [Column(Position = -3)] - public DateTime UpdateTime { get; set; } + public virtual DateTime UpdateTime { get; set; } /// /// 逻辑删除 /// [Column(Position = -2)] - public bool IsDeleted { get; set; } + public virtual bool IsDeleted { get; set; } /// /// 排序 /// [Column(Position = -1)] - public int Sort { get; set; } - - /// - /// 开启工作单元事务 - /// - /// - public static IUnitOfWork Begin() => Begin(null); - /// - /// 开启工作单元事务 - /// - /// 事务等级 - /// - public static IUnitOfWork Begin(IsolationLevel? level) - { - var uow = Orm.CreateUnitOfWork(); - uow.IsolationLevel = level; - CurrentUnitOfWork = uow; - return uow; - } - - static readonly AsyncLocal _AsyncUnitOfWork = new AsyncLocal(); - static readonly AsyncLocal _AsyncTenantId = new AsyncLocal(); - /// - /// 获取或设置当前租户id - /// - public static string CurrentTenantId - { - get => _AsyncTenantId.Value; - set => _AsyncTenantId.Value = value; - } - /// - /// 获取或设置当前租户id - /// - public static IUnitOfWork CurrentUnitOfWork - { - get => _AsyncUnitOfWork.Value; - set => _AsyncUnitOfWork.Value = value; - } - } - - /// - /// 租户 - /// - public interface ITenant - { - /// - /// 租户id - /// - string TenantId { get; set; } + public virtual int Sort { get; set; } } + [Table(DisableSyncStructure = true)] public abstract class BaseEntityReadOnly : BaseEntity where TEntity : class { /// @@ -153,9 +108,7 @@ namespace FreeSql { var select = Orm.Select() .TrackToList(TrackToList) //自动为每个元素 Attach - .WithTransaction(CurrentUnitOfWork?.GetOrBeginTransaction(false)); - if (string.IsNullOrEmpty(CurrentTenantId) == false) - select.WhereCascade(a => (a as ITenant).TenantId == CurrentTenantId); + .WithTransaction(_resolveUow?.Invoke()?.GetOrBeginTransaction(false)); return select.WhereCascade(a => (a as BaseEntity).IsDeleted == false); } } @@ -169,6 +122,7 @@ namespace FreeSql var ie = list as IEnumerable; if (ie == null) return; var isFirst = true; + IBaseRepository berepo = null; foreach (var item in ie) { if (item == null) return; @@ -181,27 +135,29 @@ namespace FreeSql if (Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; if (item is BaseEntity == false) return; } - (item as BaseEntity)?.Attach(); + var beitem = item as BaseEntity; + if (beitem != null) + { + if (berepo == null) berepo = Orm.GetRepository(); + beitem.Repository = berepo; + beitem.Attach(); + } } return; } if (ls.Any() == false) return; if (ls.FirstOrDefault() is BaseEntity == false) return; if (Orm.CodeFirst.GetTableByEntity(typeof(TEntity))?.Primarys.Any() != true) return; + IBaseRepository repo = null; foreach (var item in ls) - (item as BaseEntity)?.Attach(); - } - - /// - /// 设置当前租户id - /// - protected void SetTenantId() - { - if (string.IsNullOrEmpty(CurrentTenantId) == false) { - var ten = this as ITenant; - if (ten != null) - ten.TenantId = CurrentTenantId; + var beitem = item as BaseEntity; + if (beitem != null) + { + if (repo == null) repo = Orm.GetRepository(); + beitem.Repository = repo; + beitem.Attach(); + } } } @@ -233,11 +189,8 @@ namespace FreeSql this.Repository = Orm.GetRepository(); var item = this as TEntity; - this.SetTenantId(); this.Repository.Attach(item); return item; } } } - -#endif \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs deleted file mode 100644 index a2b5231c..00000000 --- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs +++ /dev/null @@ -1,168 +0,0 @@ -#if netcore - -using FreeSql; -using FreeSql.DataAnnotations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FreeSql -{ - /// - /// 树状基类 - /// - /// - /// - [Table(DisableSyncStructure = true)] - public abstract class BaseEntityTree : BaseEntity where TEntity : class - { - /// - /// 父级id - /// - public TKey ParentId - { - get => _ParentId; - set - { - if (Equals(value, default(TKey)) == false && Equals(value, Id)) - throw new ArgumentException("ParentId 值不能与 Id 相同"); - _ParentId = value; - } - } - public TEntity Parent { get; set; } - private TKey _ParentId; - - /// - /// 下级列表 - /// - [Navigate("ParentId")] - public List Childs { get; set; } - - /// - /// 名称 - /// - public string Name { get; set; } - /// - /// 名称:技术部-前端 - /// - public string FullName { get; set; } - - public List GetAllChilds() => Select.WhereDynamic(this) - .IncludeMany(a => (a as BaseEntityTree).Childs, - t1 => t1.IncludeMany(a1 => (a1 as BaseEntityTree).Childs, - t2 => t2.IncludeMany(a2 => (a2 as BaseEntityTree).Childs, - t3 => t3.IncludeMany(a3 => (a3 as BaseEntityTree).Childs, - t4 => t4.IncludeMany(a4 => (a4 as BaseEntityTree).Childs, - t5 => t5.IncludeMany(a5 => (a5 as BaseEntityTree).Childs, - t6 => t6.IncludeMany(a6 => (a6 as BaseEntityTree).Childs, - t7 => t7.IncludeMany(a7 => (a7 as BaseEntityTree).Childs, - t8 => t8.IncludeMany(a8 => (a8 as BaseEntityTree).Childs, - t9 => t9.IncludeMany(a9 => (a9 as BaseEntityTree).Childs, - t10 => t10.IncludeMany(a10 => (a10 as BaseEntityTree).Childs))))))))))).ToList() - .SelectMany(a => (a as BaseEntityTree).Childs - .SelectMany(a1 => (a1 as BaseEntityTree)?.Childs - .SelectMany(a2 => (a2 as BaseEntityTree)?.Childs - .SelectMany(a3 => (a3 as BaseEntityTree)?.Childs - .SelectMany(a4 => (a4 as BaseEntityTree)?.Childs - .SelectMany(a5 => (a5 as BaseEntityTree)?.Childs - .SelectMany(a6 => (a6 as BaseEntityTree)?.Childs - .SelectMany(a7 => (a7 as BaseEntityTree)?.Childs - .SelectMany(a8 => (a8 as BaseEntityTree)?.Childs - .SelectMany(a9 => (a9 as BaseEntityTree)?.Childs - .SelectMany(a10 => (a10 as BaseEntityTree)?.Childs))))))))))).Where(a => a != null).ToList(); - - protected void RefershFullName() - { - var buf = new List(); - buf.Add(this as TEntity); - buf.AddRange(this.GetAllChilds()); - var repo = Orm.GetRepository(); - repo.UnitOfWork = CurrentUnitOfWork; - buf = repo.Select.WhereDynamic(buf) - .Include(a => ((((((((((a as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent - as BaseEntityTree).Parent).ToList(true); - foreach (var item in buf) - { - var up = item as BaseEntityTree; - up.Name = up.Name; - var cur = up.Parent as BaseEntityTree; - while (cur != null) - { - up.Name = $"{cur.Name}-{up.Name}"; - cur = cur.Parent as BaseEntityTree; - } - } - repo.Update(buf); - } - - T UpdateIsDelete(bool value, Func, List, T> func) - { - var childs = GetAllChilds(); - childs.Add(this as TEntity); - var repo = Orm.GetRepository(); - repo.UnitOfWork = CurrentUnitOfWork; - repo.Attach(childs); - foreach (var item in childs) - (item as BaseEntity).IsDeleted = false; - return func(repo, childs); - } - public override bool Delete(bool physicalDelete = false) => UpdateIsDelete(true, (repo, chis) => repo.Update(chis)) > 0; - async public override Task DeleteAsync(bool physicalDelete = false) => await UpdateIsDelete(true, (repo, chis) => repo.UpdateAsync(chis)) > 0; - - public override bool Restore() => UpdateIsDelete(false, (repo, chis) => repo.Update(chis)) > 0; - async public override Task RestoreAsync() => await UpdateIsDelete(false, (repo, chis) => repo.UpdateAsync(chis)) > 0; - - public override TEntity Insert() - { - var ret = base.Insert(); - RefershFullName(); - return ret; - } - async public override Task InsertAsync() - { - var ret = await base.InsertAsync(); - RefershFullName(); - return ret; - } - public override bool Update() - { - var old = Find(this.Id) as BaseEntityTree; - var ret = base.Update(); - if (old.Name != this.Name || Equals(old.ParentId, old.ParentId) == false) RefershFullName(); - return ret; - } - async public override Task UpdateAsync() - { - var old = Find(this.Id) as BaseEntityTree; - var ret = await base.UpdateAsync(); - if (old.Name != this.Name || Equals(old.ParentId, old.ParentId) == false) RefershFullName(); - return ret; - } - public override TEntity Save() - { - var old = Find(this.Id) as BaseEntityTree; - var ret = base.Save(); - if (old.Name != this.Name || Equals(old.ParentId, old.ParentId) == false) RefershFullName(); - return ret; - } - async public override Task SaveAsync() - { - var old = Find(this.Id) as BaseEntityTree; - var ret = await base.SaveAsync(); - if (old.Name != this.Name || Equals(old.ParentId, old.ParentId) == false) RefershFullName(); - return ret; - } - } -} - -#endif \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj index f050c5f2..f6898685 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj +++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj @@ -1,7 +1,7 @@  - netcoreapp31;netcoreapp21;net4.0; + netstandard2.0;net45;net40 1.5.0-preview0509 true ncc;YeXiangQin @@ -34,12 +34,8 @@ - - - - - - netcore + + net40 diff --git a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml index a2b0bbc5..8b44d128 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml +++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml @@ -68,6 +68,12 @@ + + + 【完整】保存导航属性,子表 + + 导航属性名 + 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类 @@ -125,6 +131,12 @@ + + + 【完整】保存导航属性,子表 + + 导航属性名 + 包括 CreateTime/UpdateTime/IsDeleted 的实体基类 @@ -135,7 +147,7 @@ 全局 IFreeSql orm 对象 - + 初始化BaseEntity BaseEntity.Initialization(new FreeSqlBuilder() @@ -147,6 +159,7 @@ .Build()); IFreeSql orm 对象 + 工作单元(事务)委托,如果不使用事务请传 null解释:由于AsyncLocal平台兼容不好,所以交给外部管理 @@ -168,45 +181,12 @@ 排序 - - - 开启工作单元事务 - - - - - - 开启工作单元事务 - - 事务等级 - - - - - 获取或设置当前租户id - - - - - 租户 - - - - - 租户id - - 查询数据 - - - 设置当前租户id - - 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") @@ -232,32 +212,5 @@ 附加实体,在更新数据时,只更新变化的部分 - - - 树状基类 - - - - - - - 父级id - - - - - 下级列表 - - - - - 名称 - - - - - 名称:技术部-前端 - - diff --git a/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntity.cs b/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntity.cs deleted file mode 100644 index 41742013..00000000 --- a/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntity.cs +++ /dev/null @@ -1,122 +0,0 @@ -#if netcore -#else - -using FreeSql; -using FreeSql.DataAnnotations; -using System; -using System.Data; -using System.Diagnostics; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; - -namespace FreeSql -{ - /// - /// 包括 CreateTime/UpdateTime/IsDeleted、CRUD 方法、以及 ID 主键定义 的实体基类 - /// - /// 当 TKey 为 int/long 时,Id 主键被设为自增值主键 - /// - /// - /// - [Table(DisableSyncStructure = true)] - public abstract class BaseEntity : BaseEntity where TEntity : class - { - static BaseEntity() - { - var tkeyType = typeof(TKey)?.NullableTypeOrThis(); - if (tkeyType == typeof(int) || tkeyType == typeof(long)) - Orm.CodeFirst.ConfigEntity(typeof(TEntity), - t => t.Property("Id").IsIdentity(true)); - } - - /// - /// 主键 - /// - [Column(Position = 1)] - public virtual TKey Id { get; set; } - - /// - /// 根据主键值获取数据 - /// - /// - /// - public static TEntity Find(TKey id) - { - var item = Select.WhereDynamic(id).First(); - (item as BaseEntity)?.Attach(); - return item; - } - } - - /// - /// 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类 - /// - /// - [Table(DisableSyncStructure = true)] - public abstract class BaseEntity : BaseEntityReadOnly where TEntity : class - { - bool DeletedPrivate(bool value) - { - if (this.Repository == null) - return Orm.Delete(this as TEntity) - .ExecuteAffrows() == 1; - - return this.Repository.Delete(this as TEntity) == 1; - } - /// - /// 删除数据 - /// - /// - public virtual bool Delete() => this.DeletedPrivate(true); - - /// - /// 更新数据 - /// - /// - public virtual bool Update() - { - if (this.Repository == null) - return Orm.Update() - .SetSource(this as TEntity).ExecuteAffrows() == 1; - - return this.Repository.Update(this as TEntity) == 1; - } - /// - /// 插入数据 - /// - public virtual TEntity Insert() - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - return this.Repository.Insert(this as TEntity); - } - - /// - /// 更新或插入 - /// - /// - public virtual TEntity Save() - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - return this.Repository.InsertOrUpdate(this as TEntity); - } - - /// - /// 【完整】保存导航属性,子表 - /// - /// 导航属性名 - public virtual void SaveMany(string navigatePropertyName) - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - this.Repository.SaveMany(this as TEntity, navigatePropertyName); - } - } -} - -#endif \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntityReadOnly.cs b/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntityReadOnly.cs deleted file mode 100644 index 7464f2fb..00000000 --- a/Extensions/FreeSql.Extensions.BaseEntity/Net40/BaseEntityReadOnly.cs +++ /dev/null @@ -1,130 +0,0 @@ -#if netcore -#else - -using FreeSql.DataAnnotations; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Threading; - -namespace FreeSql -{ - /// - /// 包括 CreateTime/UpdateTime/IsDeleted 的实体基类 - /// - [Table(DisableSyncStructure = true)] - public abstract class BaseEntity - { - static IFreeSql _ormPriv; - /// - /// 全局 IFreeSql orm 对象 - /// - public static IFreeSql Orm => _ormPriv ?? throw new Exception(@"使用前请初始化 BaseEntity.Initialization(new FreeSqlBuilder() -.UseAutoSyncStructure(true) -.UseConnectionString(DataType.Sqlite, ""data source=test.db;max pool size=5"") -.Build());"); - - /// - /// 初始化BaseEntity - /// BaseEntity.Initialization(new FreeSqlBuilder() - /// - /// .UseAutoSyncStructure(true) - /// - /// .UseConnectionString(DataType.Sqlite, "data source=test.db;max pool size=5") - /// - /// .Build()); - /// - /// IFreeSql orm 对象 - public static void Initialization(IFreeSql fsql) - { - _ormPriv = fsql; - _ormPriv.Aop.CurdBefore += (s, e) => Trace.WriteLine(e.Sql + "\r\n"); - } - } - - public abstract class BaseEntityReadOnly : BaseEntity where TEntity : class - { - /// - /// 查询数据 - /// - /// - public static ISelect Select - { - get - { - var select = Orm.Select().TrackToList(TrackToList); //自动为每个元素 Attach; - return select; - } - } - - static void TrackToList(object list) - { - if (list == null) return; - var ls = list as IList; - if (ls == null) - { - var ie = list as IEnumerable; - if (ie == null) return; - var isFirst = true; - foreach (var item in ie) - { - if (item == null) return; - if (isFirst) - { - isFirst = false; - var itemType = item.GetType(); - if (itemType == typeof(object)) return; - if (itemType.FullName.Contains("FreeSqlLazyEntity__")) itemType = itemType.BaseType; - if (Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; - if (item is BaseEntity == false) return; - } - (item as BaseEntity)?.Attach(); - } - return; - } - if (ls.Any() == false) return; - if (ls.FirstOrDefault() is BaseEntity == false) return; - if (Orm.CodeFirst.GetTableByEntity(typeof(TEntity))?.Primarys.Any() != true) return; - foreach (var item in ls) - (item as BaseEntity)?.Attach(); - } - - /// - /// 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") - /// - /// lambda表达式 - /// - public static ISelect Where(Expression> exp) => Select.Where(exp); - /// - /// 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com") - /// - /// true 时生效 - /// lambda表达式 - /// - public static ISelect WhereIf(bool condition, Expression> exp) => Select.WhereIf(condition, exp); - - /// - /// 仓储对象 - /// - protected IBaseRepository Repository { get; set; } - - /// - /// 附加实体,在更新数据时,只更新变化的部分 - /// - public TEntity Attach() - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - var item = this as TEntity; - this.Repository.Attach(item); - return item; - } - } -} - -#endif \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/readme.md b/Extensions/FreeSql.Extensions.BaseEntity/readme.md index a9ace8ac..1c347ded 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/readme.md +++ b/Extensions/FreeSql.Extensions.BaseEntity/readme.md @@ -42,7 +42,7 @@ public class UserGroup : BaseEntity ```csharp public class UserGroup : BaseEntity { - [Column(IsIdentity = false)] + [Column(IsIdentity = false)] public override int Id { get; set; } public string GroupName { get; set; } } @@ -90,3 +90,37 @@ var items = UserGroup.Where(a => a.Id > 10).ToList(); 支持多表查询时,软删除条件会附加在每个表中; > 有关更多查询方法,请参考资料:https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2 + +# 事务建议 + +由于 AsyncLocal 平台兼容不好,所以交给外部管理。 + +```csharp +static AsyncLocal _asyncUow = new AsyncLocal(); + +BaseEntity.Initialization(fsql, () => _asyncUow.Value); +``` + +在 Scoped 开始时: _asyncUow.Value = fsql.CreateUnitOfWork(); (也可以使用 UnitOfWorkManager 对象获取 uow) + +在 Scoped 结束时:_asyncUow.Value = null; + +如下: + +```csharp +using (var uow = fsql.CreateUnitOfWork()) +{ + _asyncUow.Value = uow; + + try + { + //todo ... + } + finally + { + _asyncUow.Value = null; + } + + uow.Commit(); +} +``` diff --git a/FreeSql.Tests.VB/UnitTest1.vb b/FreeSql.Tests.VB/UnitTest1.vb index da79ebdf..c8966d58 100644 --- a/FreeSql.Tests.VB/UnitTest1.vb +++ b/FreeSql.Tests.VB/UnitTest1.vb @@ -39,7 +39,7 @@ Namespace FreeSql.Tests.VB Dim List9 = g.sqlserver.Select(Of Testvb).IncludeMany(Function(a) a.Testvb2s).ToList() - BaseEntity.Initialization(g.sqlserver) + BaseEntity.Initialization(g.sqlserver, Nothing) Dim cowR As CowRecord = New CowRecord cowR.Id = 1 cowR.Lact = 1 diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs b/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs index 663056ed..c723b02b 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs @@ -24,7 +24,7 @@ namespace FreeSql.Tests g.sqlite.Delete().Where("1=1").ExecuteAffrows(); g.sqlite.Delete().Where("1=1").ExecuteAffrows(); g.sqlite.Delete().Where("1=1").ExecuteAffrows(); - BaseEntity.Initialization(g.sqlite); + BaseEntity.Initialization(g.sqlite, null); userinfo user = new userinfo { userid = 1, badgenumber = "", Name="", IDCardNo="" }; user.Insert();