From 096ecdfb84bad3c2afc909fb511794b64d2d359f Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Mon, 29 Jan 2024 09:17:49 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20DbContextOptions.Audit?= =?UTF-8?q?Value=20=E5=9F=BA=E4=BA=8E=20Ioc=20Scoped=20=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E5=80=BC=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AggregateRootRepositoryAsync.cs | 23 +- .../AggregateRootRepositorySync.cs | 23 +- .../FreeSql.Extensions.AggregateRoot.csproj | 4 +- .../DbContext/DbContextOptions.cs | 30 ++ FreeSql.DbContext/DbSet/DbSet.cs | 27 +- FreeSql.DbContext/FreeSql.DbContext.xml | 29 ++ .../UnitOfWork/UnitOfWorkManager.cs | 1 + FreeSql/Extensions/FreeSqlGlobalExtensions.cs | 1 + FreeSql/FreeSql.xml | 288 ++++++++++++++++++ 9 files changed, 417 insertions(+), 9 deletions(-) diff --git a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositoryAsync.cs b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositoryAsync.cs index 97b64bb8..6c2a38e5 100644 --- a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositoryAsync.cs +++ b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositoryAsync.cs @@ -263,7 +263,28 @@ namespace FreeSql })); } - var updateLogDict = tracking.UpdateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.UpdateLog.Where(b => b.Item1 == a.Key).Select(b => new + if (_repository.DbContextOptions.AuditValueHandler != null) + { + foreach (var log in tracking.UpdateLog) + { + var table = Orm.CodeFirst.GetTableByEntity(log.Item1); + _repository.DbContextOptions.AuditValueHandler(this, new DbContextAuditValueEventArgs(Aop.AuditValueType.Update, log.Item1, log.Item3)); + log.Item4.Clear(); + foreach (var col in table.ColumnsByCs.Values) + { + if (table.ColumnsByCsIgnore.ContainsKey(col.CsName)) continue; + if (table.ColumnsByCs.ContainsKey(col.CsName)) + { + if (col.Attribute.IsVersion) continue; + var propvalBefore = table.GetPropertyValue(log.Item2, col.CsName); + var propvalAfter = table.GetPropertyValue(log.Item3, col.CsName); + if (AggregateRootUtils.CompareEntityPropertyValue(col.CsType, propvalBefore, propvalAfter) == false) log.Item4.Add(col.CsName); + continue; + } + } + } + } + var updateLogDict = tracking.UpdateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.UpdateLog.Where(b => b.Item1 == a.Key && b.Item4.Any()).Select(b => new { BeforeObject = b.Item2, AfterObject = b.Item3, diff --git a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositorySync.cs b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositorySync.cs index 9f747fe7..c6fba292 100644 --- a/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositorySync.cs +++ b/Extensions/FreeSql.Extensions.AggregateRoot/AggregateRootRepository/AggregateRootRepositorySync.cs @@ -314,7 +314,28 @@ namespace FreeSql })); } - var updateLogDict = tracking.UpdateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.UpdateLog.Where(b => b.Item1 == a.Key).Select(b => new + if (_repository.DbContextOptions.AuditValueHandler != null) + { + foreach (var log in tracking.UpdateLog) + { + var table = Orm.CodeFirst.GetTableByEntity(log.Item1); + _repository.DbContextOptions.AuditValueHandler(this, new DbContextAuditValueEventArgs(Aop.AuditValueType.Update, log.Item1, log.Item3)); + log.Item4.Clear(); + foreach (var col in table.ColumnsByCs.Values) + { + if (table.ColumnsByCsIgnore.ContainsKey(col.CsName)) continue; + if (table.ColumnsByCs.ContainsKey(col.CsName)) + { + if (col.Attribute.IsVersion) continue; + var propvalBefore = table.GetPropertyValue(log.Item2, col.CsName); + var propvalAfter = table.GetPropertyValue(log.Item3, col.CsName); + if (AggregateRootUtils.CompareEntityPropertyValue(col.CsType, propvalBefore, propvalAfter) == false) log.Item4.Add(col.CsName); + continue; + } + } + } + } + var updateLogDict = tracking.UpdateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.UpdateLog.Where(b => b.Item1 == a.Key && b.Item4.Any()).Select(b => new { BeforeObject = b.Item2, AfterObject = b.Item3, diff --git a/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj b/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj index 73705458..f47e0668 100644 --- a/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj +++ b/Extensions/FreeSql.Extensions.AggregateRoot/FreeSql.Extensions.AggregateRoot.csproj @@ -23,12 +23,12 @@ - + - + diff --git a/FreeSql.DbContext/DbContext/DbContextOptions.cs b/FreeSql.DbContext/DbContext/DbContextOptions.cs index 58ad5407..11b5445b 100644 --- a/FreeSql.DbContext/DbContext/DbContextOptions.cs +++ b/FreeSql.DbContext/DbContext/DbContextOptions.cs @@ -1,4 +1,5 @@  +using FreeSql.Internal.Model; using System; using System.Collections.Generic; using System.Linq; @@ -47,5 +48,34 @@ namespace FreeSql /// 实体变化事件 /// public Action> OnEntityChange { get; set; } + + /// + /// DbContext/Repository 审计值事件,适合 Scoped IOC 中获取登陆信息 + /// + public event EventHandler AuditValue; + public EventHandler AuditValueHandler => AuditValue; + } + + public class DbContextAuditValueEventArgs : EventArgs + { + public DbContextAuditValueEventArgs(Aop.AuditValueType auditValueType, Type entityType, object obj) + { + this.AuditValueType = auditValueType; + this.EntityType = entityType; + this.Object = obj; + } + + /// + /// 类型 + /// + public Aop.AuditValueType AuditValueType { get; } + /// + /// 类型 + /// + public Type EntityType { get; } + /// + /// 实体对象 + /// + public object Object { get; } } } diff --git a/FreeSql.DbContext/DbSet/DbSet.cs b/FreeSql.DbContext/DbSet/DbSet.cs index aa84e759..71e54eb5 100644 --- a/FreeSql.DbContext/DbSet/DbSet.cs +++ b/FreeSql.DbContext/DbSet/DbSet.cs @@ -66,16 +66,27 @@ namespace FreeSql if (_db.Options.NoneParameter != null) insert.NoneParameter(_db.Options.NoneParameter.Value); return insert; } - protected virtual IInsert OrmInsert(TEntity data) + protected virtual IInsert OrmInsert(TEntity entity) { var insert = OrmInsert(); - if (data != null) (insert as InsertProvider)._source.Add(data); //防止 Aop.AuditValue 触发两次 + if (entity != null) + { + (insert as InsertProvider)._source.Add(entity); //防止 Aop.AuditValue 触发两次 + if (_db.Options.AuditValueHandler != null) + _db.Options.AuditValueHandler(_db, new DbContextAuditValueEventArgs(Aop.AuditValueType.Insert, _table.Type, entity)); + } return insert; } - protected virtual IInsert OrmInsert(IEnumerable data) + protected virtual IInsert OrmInsert(IEnumerable entitys) { var insert = OrmInsert(); - if (data != null) (insert as InsertProvider)._source.AddRange(data.Where(a => a != null)); //防止 Aop.AuditValue 触发两次 + if (entitys != null) + { + (insert as InsertProvider)._source.AddRange(entitys.Where(a => a != null)); //防止 Aop.AuditValue 触发两次 + if (_db.Options.AuditValueHandler != null) + foreach (var item in entitys) + _db.Options.AuditValueHandler(_db, new DbContextAuditValueEventArgs(Aop.AuditValueType.Insert, _table.Type, item)); + } return insert; } @@ -84,7 +95,13 @@ namespace FreeSql var update = _db.OrmOriginal.Update().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); if (_db.Options.NoneParameter != null) update.NoneParameter(_db.Options.NoneParameter.Value); if (_db.Options.EnableGlobalFilter == false) update.DisableGlobalFilter(); - if (entitys != null) (update as UpdateProvider)._source.AddRange(entitys.Where(a => a != null)); //防止 Aop.AuditValue 触发两次 + if (entitys != null) + { + (update as UpdateProvider)._source.AddRange(entitys.Where(a => a != null)); //防止 Aop.AuditValue 触发两次 + if (_db.Options.AuditValueHandler != null) + foreach (var item in entitys) + _db.Options.AuditValueHandler(_db, new DbContextAuditValueEventArgs(Aop.AuditValueType.Update, _table.Type, item)); + } return update; } protected virtual IDelete OrmDelete(object dywhere) diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 1567ec63..3de63092 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -130,6 +130,26 @@ 实体变化事件 + + + DbContext/Repository 审计值事件,适合 Scoped IOC 中获取登陆信息 + + + + + 类型 + + + + + 类型 + + + + + 实体对象 + + 动态Type,在使用 DbSet<object> 后使用本方法,指定实体类型 @@ -806,5 +826,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs b/FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs index 375a0e4f..dd5a16aa 100644 --- a/FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs +++ b/FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs @@ -72,6 +72,7 @@ namespace FreeSql { var repoInfo = new RepoInfo(repository); repository.UnitOfWork = Current; + if (_repos.Any(a => a.Repository == repository)) return; _repos.Add(repoInfo); } void SetAllRepositoryUow() diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index 25c447f1..0a2e1296 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -163,6 +163,7 @@ public static partial class FreeSqlGlobalExtensions public static object CreateInstanceGetDefaultValue(this Type that) { if (that == null) return null; + if (that == typeof(void)) return null; if (that == typeof(string)) return default(string); if (that == typeof(Guid)) return default(Guid); if (that == typeof(byte[])) return default(byte[]); diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 4d006dda..8f213e5c 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1104,6 +1104,82 @@ + + + 动态创建实体类型 + + + + + 配置Class + + 类名 + 类标记的特性[Table(Name = "xxx")] [Index(xxxx)] + + + + + 配置属性 + + 属性名称 + 属性类型 + 属性标记的特性-支持多个 + + + + + 配置属性 + + 属性名称 + 属性类型 + 该属性是否重写父类属性 + 属性标记的特性-支持多个 + + + + + 配置属性 + + 属性名称 + 属性类型 + 该属性是否重写父类属性 + 属性默认值 + 属性标记的特性-支持多个 + + + + + 配置父类 + + 父类类型 + + + + + Override属性 + + + + + + Emit动态创建出Class - Type + + + + + + 首字母小写 + + + + + + + 首字母大写 + + + + 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null @@ -3283,6 +3359,13 @@ + + + 执行SQL语句,返回更新后的记录 + 注意:此方法只有 Postgresql/SqlServer 有效果 + + + 指定事务对象 @@ -3627,6 +3710,177 @@ + + + 测试数据库是否连接正确,本方法执行如下命令: + MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1 + Oracle: SELECT 1 FROM dual + + 命令超时设置(秒) + + true: 成功, false: 失败 + + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + + 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 在【主库】执行 + + + + + + + + + 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 在【主库】执行 + + + + + + + + + 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + + + 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 可自定义解析表达式 @@ -4626,6 +4880,12 @@ 超时 + + + 获取资源 + + + 使用完毕后,归还资源 @@ -4701,6 +4961,12 @@ 资源对象 + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + 归还对象给对象池的时候触发 @@ -5631,6 +5897,28 @@ 请使用 fsql.InsertDict(dict) 方法插入字典数据 + + + 动态构建Class Type + + + + + + 根据字典,创建 table 对应的实体对象 + + + + + + + + 根据实体对象,创建 table 对应的字典 + + + + + C#: that >= between && that <= and