diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs
index 1015bd55..213fb038 100644
--- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs
+++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs
@@ -7,65 +7,129 @@ using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
-///
-/// 包括 CreateTime/UpdateTime/IsDeleted 的实体基类
-///
-[Table(DisableSyncStructure = true)]
-public abstract class BaseEntity
+namespace FreeSql
{
- static IFreeSql _ormPriv;
///
- /// 全局 IFreeSql orm 对象
+ /// 包括 CreateTime/UpdateTime/IsDeleted、CRUD 方法、以及 ID 主键定义 的实体基类
+ ///
+ /// 当 TKey 为 int/long 时,Id 主键被设为自增值主键
///
- 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)
+ ///
+ ///
+ [Table(DisableSyncStructure = true)]
+ public abstract class BaseEntity : BaseEntity where TEntity : class
{
- _ormPriv = fsql;
- _ormPriv.Aop.CurdBefore += (s, e) => Trace.WriteLine(e.Sql + "\r\n");
+ 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));
+ }
+
+ ///
+ /// 主键
+ ///
+ public virtual TKey Id { get; set; }
+
+ ///
+ /// 根据主键值获取数据
+ ///
+ ///
+ ///
+ async public static Task FindAsync(TKey id)
+ {
+ var item = await Select.WhereDynamic(id).FirstAsync();
+ (item as BaseEntity)?.Attach();
+ return item;
+ }
+
+ ///
+ /// 根据主键值获取数据
+ ///
+ ///
+ ///
+ public static TEntity Find(TKey id)
+ {
+ var item = Select.WhereDynamic(id).First();
+ (item as BaseEntity)?.Attach();
+ return item;
+ }
}
///
- /// 创建时间
+ /// 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类
///
- public DateTime CreateTime { get; set; }
- ///
- /// 更新时间
- ///
- public DateTime UpdateTime { get; set; }
- ///
- /// 逻辑删除
- ///
- public bool IsDeleted { get; set; }
-
- ///
- /// 开启工作单元事务
- ///
- ///
- public static IUnitOfWork Begin() => Begin(null);
- ///
- /// 开启工作单元事务
- ///
- /// 事务等级
- ///
- public static IUnitOfWork Begin(IsolationLevel? level)
+ ///
+ [Table(DisableSyncStructure = true)]
+ public abstract class BaseEntity : BaseEntityAsync where TEntity : class
{
- var uow = Orm.CreateUnitOfWork();
- uow.IsolationLevel = level;
- return uow;
+ bool UpdateIsDeleted(bool value)
+ {
+ if (this.Repository == null)
+ return Orm.Update(this as TEntity)
+ .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
+ .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1;
+
+ this.SetTenantId();
+ this.IsDeleted = value;
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.Update(this as TEntity) == 1;
+ }
+ ///
+ /// 删除数据
+ ///
+ ///
+ public virtual bool Delete() => this.UpdateIsDeleted(true);
+ ///
+ /// 恢复删除的数据
+ ///
+ ///
+ public virtual bool Restore() => this.UpdateIsDeleted(false);
+
+ ///
+ /// 更新数据
+ ///
+ ///
+ public virtual bool Update()
+ {
+ this.UpdateTime = DateTime.Now;
+ if (this.Repository == null)
+ return Orm.Update()
+ .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
+ .SetSource(this as TEntity).ExecuteAffrows() == 1;
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.Update(this as TEntity) == 1;
+ }
+ ///
+ /// 插入数据
+ ///
+ public virtual TEntity Insert()
+ {
+ this.CreateTime = DateTime.Now;
+ if (this.Repository == null)
+ this.Repository = Orm.GetRepository();
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.Insert(this as TEntity);
+ }
+
+ ///
+ /// 更新或插入
+ ///
+ ///
+ public virtual TEntity Save()
+ {
+ this.UpdateTime = DateTime.Now;
+ if (this.Repository == null)
+ this.Repository = Orm.GetRepository();
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.InsertOrUpdate(this as TEntity);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs
index 8d5f2399..4b98dca2 100644
--- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs
+++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs
@@ -1,121 +1,118 @@
using FreeSql;
using FreeSql.DataAnnotations;
using System;
-using System.Data;
-using System.Diagnostics;
-using System.Linq.Expressions;
-using System.Threading;
using System.Threading.Tasks;
-///
-/// 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步方法的实体基类
-///
-///
-[Table(DisableSyncStructure = true)]
-public abstract class BaseEntityAsync : BaseEntity where TEntity : class
+namespace FreeSql
{
///
- /// 查询数据
+ /// 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类
+ ///
+ /// 当 TKey 为 int/long 时,Id 主键被设为自增值主键
///
- ///
- public static ISelect Select => Orm.Select()
- .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction(false))
- .WhereCascade(a => (a as BaseEntity).IsDeleted == false);
- ///
- /// 查询条件,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()
+ ///
+ ///
+ [Table(DisableSyncStructure = true)]
+ public abstract class BaseEntityAsync : BaseEntityAsync where TEntity : class
{
- if (this.Repository == null)
- this.Repository = Orm.GetRepository();
+ static BaseEntityAsync()
+ {
+ var tkeyType = typeof(TKey)?.NullableTypeOrThis();
+ if (tkeyType == typeof(int) || tkeyType == typeof(long))
+ Orm.CodeFirst.ConfigEntity(typeof(TEntity),
+ t => t.Property("Id").IsIdentity(true));
+ }
- var item = this as TEntity;
- this.Repository.Attach(item);
- return item;
- }
+ ///
+ /// 主键
+ ///
+ public virtual TKey Id { get; set; }
- /** async **/
-
- async Task UpdateIsDeletedAsync(bool value)
- {
- if (this.Repository == null)
- return await Orm.Update(this as TEntity)
- .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
- .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrowsAsync() == 1;
-
- this.IsDeleted = value;
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return await this.Repository.UpdateAsync(this as TEntity) == 1;
- }
- ///
- /// 删除数据
- ///
- ///
- public virtual Task DeleteAsync() => this.UpdateIsDeletedAsync(true);
- ///
- /// 恢复删除的数据
- ///
- ///
- public virtual Task RestoreAsync() => this.UpdateIsDeletedAsync(false);
-
- ///
- /// 更新数据
- ///
- ///
- async public virtual Task UpdateAsync()
- {
- this.UpdateTime = DateTime.Now;
- if (this.Repository == null)
- return await Orm.Update()
- .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
- .SetSource(this as TEntity).ExecuteAffrowsAsync() == 1;
-
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return await this.Repository.UpdateAsync(this as TEntity) == 1;
- }
- ///
- /// 插入数据
- ///
- public virtual Task InsertAsync()
- {
- this.CreateTime = DateTime.Now;
- if (this.Repository == null)
- this.Repository = Orm.GetRepository();
-
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.InsertAsync(this as TEntity);
+ ///
+ /// 根据主键值获取数据
+ ///
+ ///
+ ///
+ async public static Task FindAsync(TKey id)
+ {
+ var item = await Select.WhereDynamic(id).FirstAsync();
+ (item as BaseEntity)?.Attach();
+ return item;
+ }
}
///
- /// 更新或插入
+ /// 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步方法的实体基类
///
- ///
- public virtual Task SaveAsync()
+ ///
+ [Table(DisableSyncStructure = true)]
+ public abstract class BaseEntityAsync : BaseEntityReadOnly where TEntity : class
{
- this.UpdateTime = DateTime.Now;
- if (this.Repository == null)
- this.Repository = Orm.GetRepository();
+ async Task UpdateIsDeletedAsync(bool value)
+ {
+ if (this.Repository == null)
+ return await Orm.Update(this as TEntity)
+ .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
+ .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrowsAsync() == 1;
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.InsertOrUpdateAsync(this as TEntity);
+ this.IsDeleted = value;
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return await this.Repository.UpdateAsync(this as TEntity) == 1;
+ }
+ ///
+ /// 删除数据
+ ///
+ ///
+ public virtual Task DeleteAsync() => this.UpdateIsDeletedAsync(true);
+ ///
+ /// 恢复删除的数据
+ ///
+ ///
+ public virtual Task RestoreAsync() => this.UpdateIsDeletedAsync(false);
+
+ ///
+ /// 更新数据
+ ///
+ ///
+ async public virtual Task UpdateAsync()
+ {
+ this.UpdateTime = DateTime.Now;
+ if (this.Repository == null)
+ return await Orm.Update()
+ .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
+ .SetSource(this as TEntity).ExecuteAffrowsAsync() == 1;
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return await this.Repository.UpdateAsync(this as TEntity) == 1;
+ }
+ ///
+ /// 插入数据
+ ///
+ public virtual Task InsertAsync()
+ {
+ this.CreateTime = DateTime.Now;
+ if (this.Repository == null)
+ this.Repository = Orm.GetRepository();
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.InsertAsync(this as TEntity);
+ }
+
+ ///
+ /// 更新或插入
+ ///
+ ///
+ public virtual Task SaveAsync()
+ {
+ this.UpdateTime = DateTime.Now;
+ if (this.Repository == null)
+ this.Repository = Orm.GetRepository();
+
+ this.SetTenantId();
+ this.Repository.UnitOfWork = UnitOfWork.Current.Value;
+ return this.Repository.InsertOrUpdateAsync(this as TEntity);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs
deleted file mode 100644
index cb1b8b3e..00000000
--- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using FreeSql;
-using FreeSql.DataAnnotations;
-using System;
-using System.Data;
-using System.Diagnostics;
-using System.Linq.Expressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-///
-/// 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类
-///
-/// 当 TKey 为 int/long 时,Id 主键被设为自增值主键
-///
-///
-///
-[Table(DisableSyncStructure = true)]
-public abstract class BaseEntityAsync : BaseEntityAsync where TEntity : class
-{
- static BaseEntityAsync()
- {
- var tkeyType = typeof(TKey)?.NullableTypeOrThis();
- if (tkeyType == typeof(int) || tkeyType == typeof(long))
- Orm.CodeFirst.ConfigEntity(typeof(TEntity),
- t => t.Property("Id").IsIdentity(true));
- }
-
- ///
- /// 主键
- ///
- public virtual TKey Id { get; set; }
-
- ///
- /// 根据主键值获取数据
- ///
- ///
- ///
- async public static Task FindAsync(TKey id)
- {
- var item = await Select.WhereDynamic(id).FirstAsync();
- (item as BaseEntity)?.Attach();
- return item;
- }
-}
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs
new file mode 100644
index 00000000..21d35c1f
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs
@@ -0,0 +1,160 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.Data;
+using System.Diagnostics;
+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 DateTime CreateTime { get; set; }
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdateTime { get; set; }
+ ///
+ /// 逻辑删除
+ ///
+ public bool IsDeleted { get; set; }
+ ///
+ /// 排序
+ ///
+ public int Sort { get; set; }
+
+ ///
+ /// 开启工作单元事务
+ ///
+ ///
+ public static IUnitOfWork Begin() => Begin(null);
+ ///
+ /// 开启工作单元事务
+ ///
+ /// 事务等级
+ ///
+ public static IUnitOfWork Begin(IsolationLevel? level)
+ {
+ var uow = Orm.CreateUnitOfWork();
+ uow.IsolationLevel = level;
+ return uow;
+ }
+
+ static readonly AsyncLocal _AsyncTenantId = new AsyncLocal();
+ ///
+ /// 获取或设置当前租户id
+ ///
+ public static string CurrentTenantId
+ {
+ get => _AsyncTenantId.Value;
+ set => _AsyncTenantId.Value = value;
+ }
+ }
+
+ ///
+ /// 租户
+ ///
+ public interface ITenant
+ {
+ ///
+ /// 租户id
+ ///
+ string TenantId { get; set; }
+ }
+
+ public abstract class BaseEntityReadOnly : BaseEntity where TEntity : class
+ {
+ ///
+ /// 查询数据
+ ///
+ ///
+ public static ISelect Select
+ {
+ get
+ {
+ var select = Orm.Select().WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction(false));
+ if (string.IsNullOrEmpty(CurrentTenantId) == false)
+ select.WhereCascade(a => (a as ITenant).TenantId == CurrentTenantId);
+ return select.WhereCascade(a => (a as BaseEntity).IsDeleted == false);
+ }
+ }
+ ///
+ /// 设置当前租户id
+ ///
+ protected void SetTenantId()
+ {
+ if (string.IsNullOrEmpty(CurrentTenantId) == false)
+ {
+ var ten = this as ITenant;
+ if (ten != null)
+ ten.TenantId = CurrentTenantId;
+ }
+ }
+
+ ///
+ /// 查询条件,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.SetTenantId();
+ this.Repository.Attach(item);
+ return item;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs
deleted file mode 100644
index eab376b7..00000000
--- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using FreeSql;
-using FreeSql.DataAnnotations;
-using System;
-using System.Data;
-using System.Diagnostics;
-using System.Linq.Expressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-///
-/// 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类
-///
-///
-[Table(DisableSyncStructure = true)]
-public abstract class BaseEntity : BaseEntityAsync where TEntity : class
-{
- bool UpdateIsDeleted(bool value)
- {
- if (this.Repository == null)
- return Orm.Update(this as TEntity)
- .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
- .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1;
-
- this.IsDeleted = value;
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.Update(this as TEntity) == 1;
- }
- ///
- /// 删除数据
- ///
- ///
- public virtual bool Delete() => this.UpdateIsDeleted(true);
- ///
- /// 恢复删除的数据
- ///
- ///
- public virtual bool Restore() => this.UpdateIsDeleted(false);
-
- ///
- /// 更新数据
- ///
- ///
- public virtual bool Update()
- {
- this.UpdateTime = DateTime.Now;
- if (this.Repository == null)
- return Orm.Update()
- .WithTransaction(UnitOfWork.Current.Value?.GetOrBeginTransaction())
- .SetSource(this as TEntity).ExecuteAffrows() == 1;
-
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.Update(this as TEntity) == 1;
- }
- ///
- /// 插入数据
- ///
- public virtual TEntity Insert()
- {
- this.CreateTime = DateTime.Now;
- if (this.Repository == null)
- this.Repository = Orm.GetRepository();
-
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.Insert(this as TEntity);
- }
-
- ///
- /// 更新或插入
- ///
- ///
- public virtual TEntity Save()
- {
- this.UpdateTime = DateTime.Now;
- if (this.Repository == null)
- this.Repository = Orm.GetRepository();
-
- this.Repository.UnitOfWork = UnitOfWork.Current.Value;
- return this.Repository.InsertOrUpdate(this as TEntity);
- }
-}
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySyncTKey.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySyncTKey.cs
deleted file mode 100644
index 359e155a..00000000
--- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySyncTKey.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using FreeSql;
-using FreeSql.DataAnnotations;
-using System;
-using System.Data;
-using System.Diagnostics;
-using System.Linq.Expressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-///
-/// 包括 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));
- }
-
- ///
- /// 主键
- ///
- public virtual TKey Id { get; set; }
-
- ///
- /// 根据主键值获取数据
- ///
- ///
- ///
- async public static Task FindAsync(TKey id)
- {
- var item = await Select.WhereDynamic(id).FirstAsync();
- (item as BaseEntity)?.Attach();
- return item;
- }
-
- ///
- /// 根据主键值获取数据
- ///
- ///
- ///
- public static TEntity Find(TKey id)
- {
- var item = Select.WhereDynamic(id).First();
- (item as BaseEntity)?.Attach();
- return item;
- }
-}
\ No newline at end of file
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs
new file mode 100644
index 00000000..fa7bd5b1
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityTree.cs
@@ -0,0 +1,164 @@
+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 = UnitOfWork.Current.Value;
+ 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 = UnitOfWork.Current.Value;
+ repo.Attach(childs);
+ foreach (var item in childs)
+ (item as BaseEntity).IsDeleted = false;
+ return func(repo, childs);
+ }
+ public override bool Delete() => UpdateIsDelete(true, (repo, chis) => repo.Update(chis)) > 0;
+ async public override Task DeleteAsync() => 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml
index 6a86cb7c..a03b9ba3 100644
--- a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml
+++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml
@@ -4,17 +4,136 @@
FreeSql.Extensions.BaseEntity
-
+
+
+ 包括 CreateTime/UpdateTime/IsDeleted、CRUD 方法、以及 ID 主键定义 的实体基类
+
+ 当 TKey 为 int/long 时,Id 主键被设为自增值主键
+
+
+
+
+
+
+ 主键
+
+
+
+
+ 根据主键值获取数据
+
+
+
+
+
+
+ 根据主键值获取数据
+
+
+
+
+
+
+ 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类
+
+
+
+
+
+ 删除数据
+
+
+
+
+
+ 恢复删除的数据
+
+
+
+
+
+ 更新数据
+
+
+
+
+
+ 插入数据
+
+
+
+
+ 更新或插入
+
+
+
+
+
+ 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类
+
+ 当 TKey 为 int/long 时,Id 主键被设为自增值主键
+
+
+
+
+
+
+ 主键
+
+
+
+
+ 根据主键值获取数据
+
+
+
+
+
+
+ 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步方法的实体基类
+
+
+
+
+
+ 删除数据
+
+
+
+
+
+ 恢复删除的数据
+
+
+
+
+
+ 更新数据
+
+
+
+
+
+ 插入数据
+
+
+
+
+ 更新或插入
+
+
+
+
包括 CreateTime/UpdateTime/IsDeleted 的实体基类
-
+
全局 IFreeSql orm 对象
-
+
初始化BaseEntity
BaseEntity.Initialization(new FreeSqlBuilder()
@@ -27,54 +146,73 @@
IFreeSql orm 对象
-
+
创建时间
-
+
更新时间
-
+
逻辑删除
-
+
+
+ 排序
+
+
+
开启工作单元事务
-
+
开启工作单元事务
事务等级
-
+
- 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步方法的实体基类
+ 获取或设置当前租户id
-
-
+
+
+ 租户
+
+
+
+
+ 租户id
+
+
+
查询数据
-
+
+
+ 设置当前租户id
+
+
+
查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
lambda表达式
-
+
查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com")
@@ -82,131 +220,42 @@
lambda表达式
-
+
仓储对象
-
+
附加实体,在更新数据时,只更新变化的部分
-
- async *
-
-
+
- 删除数据
-
-
-
-
-
- 恢复删除的数据
-
-
-
-
-
- 更新数据
-
-
-
-
-
- 插入数据
-
-
-
-
- 更新或插入
-
-
-
-
-
- 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类
-
- 当 TKey 为 int/long 时,Id 主键被设为自增值主键
+ 树状基类
-
+
- 主键
+ 父级id
-
+
- 根据主键值获取数据
-
-
-
-
-
-
- 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类
-
-
-
-
-
- 删除数据
-
-
-
-
-
- 恢复删除的数据
-
-
-
-
-
- 更新数据
-
-
-
-
-
- 插入数据
+ 下级列表
-
+
- 更新或插入
-
-
-
-
-
- 包括 CreateTime/UpdateTime/IsDeleted、CRUD 方法、以及 ID 主键定义 的实体基类
-
- 当 TKey 为 int/long 时,Id 主键被设为自增值主键
-
-
-
-
-
-
- 主键
+ 名称
-
+
- 根据主键值获取数据
+ 名称:技术部-前端
-
-
-
-
-
- 根据主键值获取数据
-
-
-