From 5fc603a18b793a040e2b1fd6ccf26826ac14c284 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Mon, 29 Jul 2019 15:35:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20FreeSql.Extensions.BaseEnt?= =?UTF-8?q?ity=20=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Examples/base_entity/BaseEntity.cs | 171 -------------- Examples/base_entity/Program.cs | 34 +-- Examples/base_entity/base_entity.csproj | 1 + Examples/base_entity/base_entity.xml | 67 ------ Examples/base_entity/readme.md | 23 +- Examples/base_entity_net45/App.config | 6 - Examples/base_entity_net45/BaseEntitySync.cs | 153 ------------- Examples/base_entity_net45/Program.cs | 15 -- .../Properties/AssemblyInfo.cs | 36 --- .../base_entity_net45.csproj | 73 ------ .../BaseEntity.cs | 71 ++++++ .../BaseEntityAsync.cs | 121 ++++++++++ .../BaseEntityAsyncTKey.cs | 44 ++++ .../BaseEntitySync.cs | 80 +++++++ .../BaseEntitySyncTKey.cs | 56 +++++ .../FreeSql.Extensions.BaseEntity.csproj | 28 +++ .../FreeSql.Extensions.BaseEntity.xml | 212 ++++++++++++++++++ .../FreeSql.Extensions.BaseEntity/readme.md | 92 ++++++++ FreeSql.sln | 28 +-- 19 files changed, 740 insertions(+), 571 deletions(-) delete mode 100644 Examples/base_entity/BaseEntity.cs delete mode 100644 Examples/base_entity_net45/App.config delete mode 100644 Examples/base_entity_net45/BaseEntitySync.cs delete mode 100644 Examples/base_entity_net45/Program.cs delete mode 100644 Examples/base_entity_net45/Properties/AssemblyInfo.cs delete mode 100644 Examples/base_entity_net45/base_entity_net45.csproj create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySyncTKey.cs create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml create mode 100644 Extensions/FreeSql.Extensions.BaseEntity/readme.md diff --git a/Examples/base_entity/BaseEntity.cs b/Examples/base_entity/BaseEntity.cs deleted file mode 100644 index 54201ec4..00000000 --- a/Examples/base_entity/BaseEntity.cs +++ /dev/null @@ -1,171 +0,0 @@ -using FreeSql; -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 -{ - private static Lazy _ormLazy = new Lazy(() => - { - var orm = new FreeSqlBuilder() - .UseAutoSyncStructure(true) - .UseNoneCommandParameter(true) - .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") - //.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2") - .Build(); - orm.Aop.CurdBefore += (s, e) => Trace.WriteLine(e.Sql + "\r\n"); - return orm; - }); - public static IFreeSql Orm => _ormLazy.Value; - - /// - /// 创建时间 - /// - 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) - { - var uow = Orm.CreateUnitOfWork(); - uow.IsolationLevel = level; - return uow; - } -} - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity : BaseEntity where TEntity : class -{ - public static ISelect Select => Orm.Select() - .WithTransaction(UnitOfWork.Current.Value?.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; } - - async Task UpdateIsDeleted(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 Delete() => this.UpdateIsDeleted(true); - /// - /// 恢复删除的数据 - /// - /// - public virtual Task Restore() => this.UpdateIsDeleted(false); - - /// - /// 附加实体,在更新数据时,只更新变化的部分 - /// - public TEntity Attach() - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - var item = this as TEntity; - this.Repository.Attach(item); - return item; - } - /// - /// 更新数据 - /// - /// - async public virtual Task Update() - { - 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 Insert() - { - 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); - } - - /// - /// 更新或插入 - /// - /// - public virtual Task Save() - { - this.UpdateTime = DateTime.Now; - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - this.Repository.UnitOfWork = UnitOfWork.Current.Value; - return this.Repository.InsertOrUpdateAsync(this as TEntity); - } -} - -[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 Find(TKey id) - { - var item = await Select.WhereDynamic(id).FirstAsync(); - (item as BaseEntity)?.Attach(); - return item; - } -} \ No newline at end of file diff --git a/Examples/base_entity/Program.cs b/Examples/base_entity/Program.cs index 0139cd32..76297250 100644 --- a/Examples/base_entity/Program.cs +++ b/Examples/base_entity/Program.cs @@ -7,39 +7,45 @@ namespace base_entity { static void Main(string[] args) { + BaseEntity.Initialization(new FreeSql.FreeSqlBuilder() + .UseAutoSyncStructure(true) + .UseConnectionString(FreeSql.DataType.Sqlite, "data source=test.db;max pool size=5") + .Build()); + Task.Run(async () => { using (var uow = BaseEntity.Begin()) { - var id = (await new User1().Save()).Id; + var id = (await new User1().SaveAsync()).Id; uow.Commit(); } var ug1 = new UserGroup(); ug1.GroupName = "分组一"; - await ug1.Insert(); + await ug1.InsertAsync(); var ug2 = new UserGroup(); ug2.GroupName = "分组二"; - await ug2.Insert(); + await ug2.InsertAsync(); var u1 = new User1(); u1.GroupId = ug1.Id; - await u1.Save(); + await u1.SaveAsync(); - await u1.Delete(); - await u1.Restore(); + await u1.DeleteAsync(); + await u1.RestoreAsync(); u1.Nickname = "x1"; - await u1.Update(); + await u1.UpdateAsync(); - var u11 = await User1.Find(u1.Id); + var u11 = await User1.FindAsync(u1.Id); u11.Description = "备注"; - await u11.Save(); + await u11.SaveAsync(); - await u11.Delete(); + await u11.DeleteAsync(); + var slslsl = Newtonsoft.Json.JsonConvert.SerializeObject(u1); var u11null = User1.Find(u1.Id); var u11s = User1.Where(a => a.Group.Id == ug1.Id).Limit(10).ToList(); @@ -54,19 +60,19 @@ namespace base_entity var r1 = new Role(); r1.Id = "管理员"; - await r1.Save(); + await r1.SaveAsync(); var r2 = new Role(); r2.Id = "超级会员"; - await r2.Save(); + await r2.SaveAsync(); var ru1 = new RoleUser1(); ru1.User1Id = u1.Id; ru1.RoleId = r1.Id; - await ru1.Save(); + await ru1.SaveAsync(); ru1.RoleId = r2.Id; - await ru1.Save(); + await ru1.SaveAsync(); var u1roles = User1.Select.IncludeMany(a => a.Roles).ToList(); var u1roles2 = User1.Select.Where(a => a.Roles.AsSelect().Any(b => b.Id == "xx")).ToList(); diff --git a/Examples/base_entity/base_entity.csproj b/Examples/base_entity/base_entity.csproj index 55a58ed3..c05b214a 100644 --- a/Examples/base_entity/base_entity.csproj +++ b/Examples/base_entity/base_entity.csproj @@ -14,6 +14,7 @@ + diff --git a/Examples/base_entity/base_entity.xml b/Examples/base_entity/base_entity.xml index f138510a..682b4b8a 100644 --- a/Examples/base_entity/base_entity.xml +++ b/Examples/base_entity/base_entity.xml @@ -4,73 +4,6 @@ base_entity - - - 创建时间 - - - - - 更新时间 - - - - - 逻辑删除 - - - - - 开启工作单元事务 - - - - - - 删除数据 - - - - - - 恢复删除的数据 - - - - - - 附加实体,在更新数据时,只更新变化的部分 - - - - - 更新数据 - - - - - - 插入数据 - - - - - 更新或插入 - - - - - - 主键 - - - - - 根据主键值获取数据 - - - - 组名 diff --git a/Examples/base_entity/readme.md b/Examples/base_entity/readme.md index 69786f07..a9ace8ac 100644 --- a/Examples/base_entity/readme.md +++ b/Examples/base_entity/readme.md @@ -24,9 +24,7 @@ BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多 # 声明 -参考 BaseEntity.cs 源码(约100行),copy 到项目中使用,然后添加 nuget 引用包: - -> dotnet add package FreeSql.Repository +> dotnet add package FreeSql.Extensions.BaseEntity > dotnet add package FreeSql.Provider.Sqlite @@ -60,25 +58,6 @@ public class User : BaseEntity } ``` -3、定义多主键的实体类型,可以在 static 构造函数中重写字段名; - -```csharp -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 string Username { get; set; } -} -``` - - # CRUD 使用 ```csharp diff --git a/Examples/base_entity_net45/App.config b/Examples/base_entity_net45/App.config deleted file mode 100644 index 88fa4027..00000000 --- a/Examples/base_entity_net45/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Examples/base_entity_net45/BaseEntitySync.cs b/Examples/base_entity_net45/BaseEntitySync.cs deleted file mode 100644 index 112c26b1..00000000 --- a/Examples/base_entity_net45/BaseEntitySync.cs +++ /dev/null @@ -1,153 +0,0 @@ -using FreeSql; -using FreeSql.DataAnnotations; -using Newtonsoft.Json; -using System; -using System.Data; -using System.Diagnostics; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity -{ - private static Lazy _ormLazy = new Lazy(() => - { - var orm = new FreeSqlBuilder() - .UseAutoSyncStructure(true) - .UseNoneCommandParameter(true) - .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") - //.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2") - .Build(); - orm.Aop.CurdBefore += (s, e) => Trace.WriteLine(e.Sql + "\r\n"); - return orm; - }); - public static IFreeSql Orm => _ormLazy.Value; - - /// - /// 创建时间 - /// - public DateTime CreateTime { get; set; } - /// - /// 更新时间 - /// - public DateTime UpdateTime { get; set; } - /// - /// 逻辑删除 - /// - public bool IsDeleted { get; set; } -} - -[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 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) - { - if (this.Repository == null) - return Orm.Update(this as TEntity) - .Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1; - - this.IsDeleted = value; - return this.Repository.Update(this as TEntity) == 1; - } - /// - /// 删除数据 - /// - /// - public virtual bool Delete() => this.UpdateIsDeleted(true); - /// - /// 恢复删除的数据 - /// - /// - public virtual bool Restore() => this.UpdateIsDeleted(false); - - /// - /// 附加实体,在更新数据时,只更新变化的部分 - /// - public TEntity Attach() - { - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - var item = this as TEntity; - this.Repository.Attach(item); - return item; - } - /// - /// 更新数据 - /// - /// - public virtual bool 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; - } - /// - /// 插入数据 - /// - public virtual TEntity Insert() - { - this.CreateTime = DateTime.Now; - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - return this.Repository.Insert(this as TEntity); - } - - /// - /// 更新或插入 - /// - /// - public virtual TEntity Save() - { - this.UpdateTime = DateTime.Now; - if (this.Repository == null) - this.Repository = Orm.GetRepository(); - - return this.Repository.InsertOrUpdate(this as TEntity); - } -} - -[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; } - - /// - /// 根据主键值获取数据 - /// - /// - /// - 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/Examples/base_entity_net45/Program.cs b/Examples/base_entity_net45/Program.cs deleted file mode 100644 index 468b7804..00000000 --- a/Examples/base_entity_net45/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace base_entity_net45 -{ - class Program - { - static void Main(string[] args) - { - } - } -} diff --git a/Examples/base_entity_net45/Properties/AssemblyInfo.cs b/Examples/base_entity_net45/Properties/AssemblyInfo.cs deleted file mode 100644 index 6fa2e439..00000000 --- a/Examples/base_entity_net45/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("base_entity_net45")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("base_entity_net45")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("7e091544-ec38-4a41-a3be-bdc693070be7")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 -// 方法是按如下所示使用“*”: : -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Examples/base_entity_net45/base_entity_net45.csproj b/Examples/base_entity_net45/base_entity_net45.csproj deleted file mode 100644 index 474dc221..00000000 --- a/Examples/base_entity_net45/base_entity_net45.csproj +++ /dev/null @@ -1,73 +0,0 @@ - - - - - Debug - AnyCPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7} - Exe - base_entity_net45 - base_entity_net45 - v4.5.2 - 512 - true - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - {82885c27-23c8-4a6e-92cf-80fe61a041e1} - FreeSql.DbContext - - - {af9c50ec-6eb6-494b-9b3b-7edba6fd0ebb} - FreeSql - - - {559b6369-1868-4a06-a590-f80ba7b80a1b} - FreeSql.Provider.Sqlite - - - - - 12.0.2 - - - - \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs new file mode 100644 index 00000000..1015bd55 --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntity.cs @@ -0,0 +1,71 @@ +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 的实体基类 +/// +[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 static IUnitOfWork Begin() => Begin(null); + /// + /// 开启工作单元事务 + /// + /// 事务等级 + /// + public static IUnitOfWork Begin(IsolationLevel? level) + { + var uow = Orm.CreateUnitOfWork(); + uow.IsolationLevel = level; + return uow; + } +} diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs new file mode 100644 index 00000000..8d5f2399 --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsync.cs @@ -0,0 +1,121 @@ +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 +{ + /// + /// 查询数据 + /// + /// + 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() + { + if (this.Repository == null) + this.Repository = Orm.GetRepository(); + + var item = this as TEntity; + this.Repository.Attach(item); + return item; + } + + /** 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); + } + + /// + /// 更新或插入 + /// + /// + public virtual Task SaveAsync() + { + this.UpdateTime = DateTime.Now; + if (this.Repository == null) + this.Repository = Orm.GetRepository(); + + this.Repository.UnitOfWork = UnitOfWork.Current.Value; + return this.Repository.InsertOrUpdateAsync(this as TEntity); + } +} diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs new file mode 100644 index 00000000..cb1b8b3e --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityAsyncTKey.cs @@ -0,0 +1,44 @@ +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/BaseEntitySync.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs new file mode 100644 index 00000000..eab376b7 --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySync.cs @@ -0,0 +1,80 @@ +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 new file mode 100644 index 00000000..359e155a --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntitySyncTKey.cs @@ -0,0 +1,56 @@ +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/FreeSql.Extensions.BaseEntity.csproj b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj new file mode 100644 index 00000000..18be6163 --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj @@ -0,0 +1,28 @@ + + + + netstandard2.0 + 0.7.16 + true + YeXiangQin + BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多表CRUD,利用继承节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用. + https://github.com/2881099/FreeSql/tree/master/Extensions/FreeSql.Extensions.BaseEntity + https://github.com/2881099/FreeSql/tree/master/Extensions/FreeSql.Extensions.BaseEntity + git + MIT + FreeSql;ORM;BaseEntity + $(AssemblyName) + $(AssemblyName) + true + true + + + + FreeSql.Extensions.BaseEntity.xml + + + + + + + diff --git a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml new file mode 100644 index 00000000..6a86cb7c --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.xml @@ -0,0 +1,212 @@ + + + + FreeSql.Extensions.BaseEntity + + + + + 包括 CreateTime/UpdateTime/IsDeleted 的实体基类 + + + + + 全局 IFreeSql orm 对象 + + + + + 初始化BaseEntity + BaseEntity.Initialization(new FreeSqlBuilder() + + .UseAutoSyncStructure(true) + + .UseConnectionString(DataType.Sqlite, "data source=test.db;max pool size=5") + + .Build()); + + IFreeSql orm 对象 + + + + 创建时间 + + + + + 更新时间 + + + + + 逻辑删除 + + + + + 开启工作单元事务 + + + + + + 开启工作单元事务 + + 事务等级 + + + + + 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步方法的实体基类 + + + + + + 查询数据 + + + + + + 查询条件,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") + + true 时生效 + lambda表达式 + + + + + 仓储对象 + + + + + 附加实体,在更新数据时,只更新变化的部分 + + + + async * + + + + 删除数据 + + + + + + 恢复删除的数据 + + + + + + 更新数据 + + + + + + 插入数据 + + + + + 更新或插入 + + + + + + 包括 CreateTime/UpdateTime/IsDeleted、CRUD 异步方法、以及 ID 主键定义 的实体基类 + + 当 TKey 为 int/long 时,Id 主键被设为自增值主键 + + + + + + + 主键 + + + + + 根据主键值获取数据 + + + + + + + 包括 CreateTime/UpdateTime/IsDeleted、以及 CRUD 异步和同步方法的实体基类 + + + + + + 删除数据 + + + + + + 恢复删除的数据 + + + + + + 更新数据 + + + + + + 插入数据 + + + + + 更新或插入 + + + + + + 包括 CreateTime/UpdateTime/IsDeleted、CRUD 方法、以及 ID 主键定义 的实体基类 + + 当 TKey 为 int/long 时,Id 主键被设为自增值主键 + + + + + + + 主键 + + + + + 根据主键值获取数据 + + + + + + + 根据主键值获取数据 + + + + + + diff --git a/Extensions/FreeSql.Extensions.BaseEntity/readme.md b/Extensions/FreeSql.Extensions.BaseEntity/readme.md new file mode 100644 index 00000000..a9ace8ac --- /dev/null +++ b/Extensions/FreeSql.Extensions.BaseEntity/readme.md @@ -0,0 +1,92 @@ +# 前言 + +尝试过 ado.net、dapper、ef,以及Repository仓储,甚至自己还写过生成器工具,以便做常规CRUD操作。 + +它们日常操作不方便之处: + +- 每次使用前需要声明,再操作; + +- 很多人一个实体类,对应一个操作类(或DAL、DbContext、Repository); + +BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多表CRUD,利用继承节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用; + +本文介绍 BaseEntity 一种极简约的 CRUD 操作方法。 + +# 功能特点 + +- 自动迁移实体结构(CodeFirst),到数据库; + +- 直接操作实体的方法,进行 CRUD 操作; + +- 简化用户定义实体类型,省去主键、常用字段的配置(如CreateTime、UpdateTime); + +- 实现单表、多表查询的软删除逻辑; + +# 声明 + +> dotnet add package FreeSql.Extensions.BaseEntity + +> dotnet add package FreeSql.Provider.Sqlite + +1、定义一个主键 int 并且自增的实体类型,BaseEntity TKey 指定为 int/long 时,会认为主键是自增; + +```csharp +public class UserGroup : BaseEntity +{ + public string GroupName { get; set; } +} +``` + +如果不想主键是自增键,可以重写属性: + +```csharp +public class UserGroup : BaseEntity +{ + [Column(IsIdentity = false)] + public override int Id { get; set; } + public string GroupName { get; set; } +} +``` +> 有关更多实体的特性配置,请参考资料:https://github.com/2881099/FreeSql/wiki/%e5%ae%9e%e4%bd%93%e7%89%b9%e6%80%a7 + +2、定义一个主键 Guid 的实体类型,保存数据时会自动产生有序不重复的 Guid 值(不用自己指定 Guid.NewGuid()); + +```csharp +public class User : BaseEntity +{ + public string UserName { get; set; } +} +``` + +# CRUD 使用 + +```csharp +//添加 +var item = new UserGroup { GroupName = "组一" }; +item.Insert(); + +//更新 +item.GroupName = "组二"; +item.Update(); + +//添加或更新 +item.Save(); + +//软删除 +item.Delete(); + +//恢复软删除 +item.Restore(); + +//根据主键获取对象 +var item = UserGroup.Find(1); + +//查询数据 +var items = UserGroup.Where(a => a.Id > 10).ToList(); +``` + +实体类型.Select 是一个查询对象,使用方法和 FreeSql.ISelect 一样; + +支持多表查询时,软删除条件会附加在每个表中; + +> 有关更多查询方法,请参考资料:https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2 diff --git a/FreeSql.sln b/FreeSql.sln index 868aa88e..78427fa6 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -56,7 +56,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.Provider.MySq EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "base_entity", "Examples\base_entity\base_entity.csproj", "{D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "base_entity_net45", "Examples\base_entity_net45\base_entity_net45.csproj", "{7E091544-EC38-4A41-A3BE-BDC693070BE7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.BaseEntity", "Extensions\FreeSql.Extensions.BaseEntity\FreeSql.Extensions.BaseEntity.csproj", "{FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -320,18 +320,18 @@ Global {D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0}.Release|x64.Build.0 = Release|Any CPU {D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0}.Release|x86.ActiveCfg = Release|Any CPU {D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0}.Release|x86.Build.0 = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|x64.ActiveCfg = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|x64.Build.0 = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|x86.ActiveCfg = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Debug|x86.Build.0 = Debug|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|Any CPU.Build.0 = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|x64.ActiveCfg = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|x64.Build.0 = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|x86.ActiveCfg = Release|Any CPU - {7E091544-EC38-4A41-A3BE-BDC693070BE7}.Release|x86.Build.0 = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|x64.Build.0 = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Debug|x86.Build.0 = Debug|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|Any CPU.Build.0 = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x64.ActiveCfg = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x64.Build.0 = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x86.ActiveCfg = Release|Any CPU + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -351,7 +351,7 @@ Global {690F89E0-A721-423F-8F5D-D262F73235EA} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {4C0973CB-BD49-4A5B-A6FE-EE0594BDD513} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} - {7E091544-EC38-4A41-A3BE-BDC693070BE7} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} + {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}