项目中使用的以一周为时间段查询自动填充时间

本文介绍了一种通过JavaScript实现的周历时间选择器。该选择器能够自动计算并设置当前周的时间范围,默认选中时间从上周一开始至本周日结束,并展示了具体的实现代码。
//默认选中时间,结束时间为当前时间的周日,开始时间为上周一
var now=new Date();
var week=now.getDay();
var day=now.getDate();
var less=day-week;
//结束时间
var endTimeDate=new Date(now.setDate(less));
var endTimeDate2=new Date(endTimeDate);
//获取开始时间
var beginTime=less-6;
var endTimes=now.setDate(endTime);
var beginTimeDate=new Date(endTimeDate2.setDate(beginTime));
setTime(beginTimeDate,"#bTime");

setTime(endTimeDate,"#endTime");


通过获取今天是周几,然后获取和本周日的差数,计算当前日期减去差数,等于周日是几号,然后通过计算出来的周日的号数减去6得到上周一的号数,然后进行数据的填充到开始时间和结束时间

<think>根据用户问题,他想要在SQLSugar中为非时间字段(如操作人ID)实现自动填充。在之前的回答中,我们已经提到SQLSugar对于时间字段有内置的自动填充(InsertServerTime和UpdateServerTime),但对于非时间字段,需要使用全局事件拦截器来实现。 参考引用[2]中提到了SQLSugar的实体配置,其中关于时间字段的自动填充使用了`[SugarColumn(InsertServerTime = true)]`和`[SugarColumn(UpdateServerTime = true)]`,但并没有提到非时间字段的自动填充。 因此,我们需要通过SQLSugar的AOP(面向切面编程)机制,在数据操作(插入或更新)执行前,对指定的字段进行赋值。 具体步骤: 1. 在实体类中定义需要自动填充的字段,例如: ```csharp [SugarTable("YourTableName")] public class YourEntity { // 其他字段... // 更新时自动填充的操作人ID [SugarColumn(ColumnName = "F_LASTMODIFYUSERID")] // 如果数据库列名和属性名不一致,使用ColumnName指定 public string LastModifyUserId { get; set; } } ``` 2. 在SqlSugarClient配置中,注册数据执行前的事件(DataExecuting),在事件中根据操作类型(插入或更新)来设置字段的值。 示例代码: ```csharp // 创建SqlSugarClient实例 var db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = "your connection string", DbType = DbType.SqlServer, // 根据数据库类型设置 IsAutoCloseConnection = true }); // 设置全局事件 db.Aop.DataExecuting += (sql, parameters) => { // 获取当前操作上下文(注意:这里需要根据SQLSugar的版本,新版本可能使用不同的方式) // 在较新的SQLSugar版本中,可以使用DataFilterContext来获取操作类型和实体信息 // 但这里我们使用另一种方式:通过AOP的DataExecuting事件参数,它提供了当前执行的SQL和参数,但获取实体信息可能不够直接 // 因此,我们更推荐使用db.Aop.OnLogExecuting事件,但该事件主要用于日志,不便于修改参数。 // 实际上,SQLSugar提供了更直接的AOP事件来处理实体操作:db.Aop.DataExecuting (重载版本) // 这里我们使用另一个重载:db.Aop.DataExecuting += (object value, DataFilterModel entityInfo) => { ... } // 但是注意:在SQLSugar中,DataExecuting事件有两个重载,一个用于日志(参数为sql和parameters),另一个用于操作实体(参数为value和entityInfo) }; // 因此,我们需要使用另一个事件:db.Aop.DataExecuting (带DataFilterModel参数的事件) // 注意:不同版本的事件可能不同,以下适用于支持DataFilterModel的版本(如SQLSugarCore 5.0.4.6及以上) // 重新注册事件(使用带DataFilterModel的事件) db.Aop.DataExecuting += (value, entityInfo) => { // entityInfo 包含操作类型和当前实体信息 if (entityInfo.OperationType == DataFilterType.Insert) { // 插入操作 // 可以在这里设置创建人ID等字段 } else if (entityInfo.OperationType == DataFilterType.Update) { // 更新操作 // 检查当前实体是否是我们要处理的类型(YourEntity) if (entityInfo.EntityValue is YourEntity entity) { // 设置更新人ID entity.LastModifyUserId = "当前用户ID"; // 这里需要从当前登录用户获取 } } }; ``` 但是,上面的方式有一个问题:当使用批量操作时,可能无法触发。而且,在事件中直接修改实体,要求实体必须是YourEntity类型,如果实体是匿名对象(例如使用Updateable<T>只更新部分字段)则不行。 因此,更通用的方法是使用实体信息(entityInfo)的PropertyName来设置,而不是直接操作实体对象。SQLSugar提供了在事件中修改字段值的方法。 改进后的通用方法: ```csharp db.Aop.DataExecuting += (value, entityInfo) => { // 如果是更新操作 if (entityInfo.OperationType == DataFilterType.Update) { // 判断实体中是否有LastModifyUserId这个属性 if (entityInfo.EntityColumnInfo != null && entityInfo.EntityColumnInfo.PropertyName == "LastModifyUserId") { // 设置该字段的值为当前用户ID entityInfo.SetValue("当前用户ID"); // 这里可以动态获取,比如从缓存或Session中 } } }; ``` 但是,注意:在更新操作中,如果使用Updateable<T>,并且只更新部分字段(即没有包含LastModifyUserId),那么该事件可能不会被触发,因为实体信息中不包含这个字段。 因此,我们需要确保在更新时,即使没有显式更新LastModifyUserId,也要自动将其加入更新字段。这可以通过全局配置来实现:在更新操作时,自动追加更新字段。 但是,在SQLSugar中,默认情况下,如果我们使用Updateable<T>(T entity)方式更新整个实体,那么所有字段都会更新(除了主键)。如果我们使用Updateable<T>().UpdateColumns(it => new { it.Name, ... })方式,则只更新指定的列。 为了确保每次更新都自动更新操作人ID,我们可以: 方法1:在业务层每次更新时,手动赋值LastModifyUserId,并确保在更新列中包含该字段(不推荐,因为容易遗漏)。 方法2:使用AOP在更新前自动设置操作人ID,并且自动将该字段加入更新列。但是,SQLSugar的AOP事件中,我们无法直接修改更新列,但可以在事件中修改实体值,然后通过全局设置让SQLSugar更新时自动包含某些字段。 实际上,SQLSugar提供了另一种机制:全局更新过滤器(Global Update Filters),可以自动追加更新字段。 例如: ```csharp // 在SqlSugarClient配置中 db.Updateable<YourEntity>() .UpdateColumns(it => new { it.LastModifyUserId }) // 这样写只能用于单个实体,不能全局 ``` 但是,SQLSugar的全局过滤器(Global Filters)主要用于查询,对于更新,我们可以使用另一种方式:使用AOP事件,在更新操作前修改实体,并确保该字段被赋值,然后使用Updateable(实体)方式更新时,它就会包含在更新字段中。 然而,如果我们使用Updateable(实体)方式,那么整个实体的字段都会被更新(除了忽略的字段)。如果我们只想更新部分字段,同时又要自动追加操作人ID,我们可以这样做: ```csharp // 在AOP事件中,我们不仅设置操作人ID,还要将该字段添加到更新列中 // 但是,在DataExecuting事件中,我们无法直接修改Updateable的更新列,因为事件发生在SQL生成之前,此时更新列已经确定。 // 因此,我们需要在更早的阶段介入,比如在db.Updateable被调用后,执行更新操作前,修改表达式树。 // SQLSugar提供了另一种AOP:OnExecutingChangeSql事件,但使用起来较复杂。 // 推荐做法:使用一个自定义的仓储基类,在基类中的Update方法中统一处理。 ``` 考虑到通用性和简单性,我们可以采用以下方案: 1. 对于需要自动填充的字段,在实体中定义。 2. 在更新操作前,通过AOP事件(DataExecuting)设置该字段的值。但是,这个事件只会在该字段被包含在更新列中时才会触发(即更新语句中包含该字段)。 3. 为了确保每次更新都包含该字段,我们可以使用全局过滤器(Global Filters)来为更新操作自动追加字段。 不过,SQLSugar并没有直接提供全局更新字段追加的功能。因此,我们可以通过封装一个通用的更新方法来实现: ```csharp public class BaseService<T> where T : class, new() { protected SqlSugarClient _db; public int Update(T entity) { // 在更新前,设置操作人ID if (entity is IHasModifier hasModifier) { hasModifier.LastModifyUserId = GetCurrentUserId(); } return _db.Updateable(entity).ExecuteCommand(); } // 同样,对于更新部分字段的方法,我们也进行封装 public int Update(Expression<Func<T, bool>> where, Expression<Func<T, T>> columns) { // 注意:columns中可能不包含操作人ID,我们需要将其加入 // 但是,表达式树合并比较复杂,我们可以先获取当前用户ID,然后创建一个新的表达式,将操作人ID的更新合并进去 var currentUserId = GetCurrentUserId(); // 假设T有LastModifyUserId属性 // 创建一个新的表达式:既包含columns中的更新,又包含LastModifyUserId的更新 // 注意:columns可能是 it => new T { Name = "abc", ... } // 我们需要将其改为 it => new T { Name = "abc", ..., LastModifyUserId = currentUserId } // 如何合并?我们可以使用表达式树合并,但比较复杂 // 或者,我们要求所有实体都实现一个接口,然后使用反射设置,但这样会破坏表达式树 // 另一种思路:先执行一次更新(不包含操作人ID),然后再单独更新操作人ID?这样不行,因为需要原子操作。 // 因此,我们建议在业务层更新时,手动包含操作人ID。或者,在AOP事件中无法解决的情况下,采用第一种整个实体更新的方式。 // 这里我们简化处理:只支持整个实体更新,或者使用UpdateColumnsIF(true)来强制包含操作人ID // 例如: return _db.Updateable<T>() .SetColumns(columns) // 先设置传入的列 .SetColumns(it => it.LastModifyUserId == currentUserId) // 再追加操作人ID .Where(where) .ExecuteCommand(); } } ``` 但是,上述方法需要所有实体都实现一个接口(如IHasModifier),并且每次更新都要通过这个基类方法。 考虑到这些复杂性,对于非时间字段的自动填充,推荐使用AOP事件,并配合以下条件: - 使用Updateable(整个实体) 的方式更新,这样就能触发DataExecuting事件,并且更新所有字段(包括自动填充的字段)。 - 或者,在更新部分字段时,显式包含操作人ID字段,这样也能触发事件。 如果项目允许,建议使用整个实体更新(注意并发问题,可以使用乐观锁)。 因此,回到AOP事件,我们采用以下方式: ```csharp db.Aop.DataExecuting += (value, entityInfo) => { // 该事件在每次操作(插入、更新、删除)前都会触发,但我们需要关注更新操作 if (entityInfo.OperationType == DataFilterType.Update) { // 判断当前操作的字段是否是LastModifyUserId(根据属性名) if (entityInfo.EntityColumnInfo.PropertyName == "LastModifyUserId") { // 设置当前用户ID entityInfo.SetValue(GetCurrentUserId()); } } // 插入操作也可以类似处理 if (entityInfo.OperationType == DataFilterType.Insert) { if (entityInfo.EntityColumnInfo.PropertyName == "CreateUserId") { entityInfo.SetValue(GetCurrentUserId()); } } }; ``` 注意:GetCurrentUserId()是一个自定义方法,用于获取当前登录用户的ID。 但是,这里有一个关键点:只有当更新语句中包含了LastModifyUserId字段时,这个事件才会被触发(因为entityInfo对应的是每个字段的赋值)。所以,如果我们更新整个实体,那么该字段会被包含。如果我们使用Updateable<T>().SetColumns(it => it.Name == "newName"),并且没有包含LastModifyUserId,那么这个事件就不会触发,也就不会设置。 因此,我们需要确保在更新时包含该字段。我们可以: 1. 在业务层,更新任何实体时,都加上LastModifyUserId字段(使用Updateable<T>().SetColumns(it=>it.Name, it=>it.LastModifyUserId))。 2. 或者,使用AOP在更上层(比如在OnLogExecuting事件中)检查更新语句,如果表中有LastModifyUserId字段,且更新语句中没有包含,则修改SQL语句追加该字段。但这种方法复杂且容易出错。 鉴于以上,如果项目要求严格,建议采用封装仓储层的方式,在基类更新方法中自动追加操作人ID字段。 总结:在SQLSugar中,非时间字段的自动填充可以通过AOP事件实现,但需要确保在操作时该字段被包含在操作列中。对于更新操作,推荐使用整个实体更新,或者显式包含操作人ID字段。 下面给出一个完整的示例: 步骤1:定义实体 ```csharp [SugarTable("YourTable")] public class YourEntity { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string Name { get; set; } // 创建人ID(插入时填充) [SugarColumn(ColumnName = "F_CREATEUSERID")] public string CreateUserId { get; set; } // 最后修改人ID(更新时填充) [SugarColumn(ColumnName = "F_LASTMODIFYUSERID")] public string LastModifyUserId { get; set; } } ``` 步骤2:在SqlSugarClient配置中注册AOP事件 ```csharp var db = new SqlSugarClient(new ConnectionConfig() { // 配置连接字符串等 }); // 获取当前用户ID的方法(根据你的系统实现) Func<string> getCurrentUserId = () => { // 例如:从HttpContext.Current.Session中获取,或者从Thread.CurrentPrincipal等 return "user001"; // 示例 }; db.Aop.DataExecuting += (value, entityInfo) => { if (entityInfo.OperationType == DataFilterType.Insert) { if (entityInfo.EntityColumnInfo.PropertyName == "CreateUserId") { entityInfo.SetValue(getCurrentUserId()); } } else if (entityInfo.OperationType == DataFilterType.Update) { if (entityInfo.EntityColumnInfo.PropertyName == "LastModifyUserId") { entityInfo.SetValue(getCurrentUserId()); } } }; ``` 步骤3:在插入和更新时,确保包含这些字段 - 插入:使用db.Insertable(entity)插入整个实体,这样CreateUserId会被触发填充。 - 更新:使用db.Updateable(entity)更新整个实体,这样LastModifyUserId会被触发填充。 或者,在更新部分字段时,显式包含LastModifyUserId字段: ```csharp db.Updateable<YourEntity>() .SetColumns(it => new YourEntity { Name = "new name", LastModifyUserId = null // 这里赋一个任意值,因为在AOP事件中会被覆盖,但必须包含该字段 }) .Where(it => it.Id == 1) .ExecuteCommand(); ``` 注意:在更新部分字段时,虽然我们显式设置了LastModifyUserId为null,但在AOP事件中会被替换为当前用户ID。如果不包含该字段,则不会触发事件。 因此,为了确保每次更新都包含该字段,我们可以创建一个扩展方法,自动追加LastModifyUserId字段到更新列。 例如: ```csharp public static class SqlSugarExtension { public static IUpdateable<T> UpdateWithModifier<T>(this IUpdateable<T> updateable) where T : class, new() { // 如果T有LastModifyUserId属性,则追加 if (typeof(T).GetProperty("LastModifyUserId") != null) { // 注意:这里我们只是设置一个占位值,实际值会在AOP事件中被替换 return updateable.SetColumns(it => new T { LastModifyUserId = null }); } return updateable; } } ``` 然后,在更新时: ```csharp db.Updateable<YourEntity>() .SetColumns(it => new YourEntity { Name = "new name" }) .UpdateWithModifier() // 追加更新LastModifyUserId .Where(it => it.Id == 1) .ExecuteCommand(); ``` 这样,就能确保更新语句中包含LastModifyUserId字段,从而触发AOP事件。 以上就是在SQLSugar中实现非时间字段自动填充的方法。根据项目的实际情况,可以选择最适合的方式。</think>在 SQLSugar 中为非时间字段(如操作人ID)实现自动填充,需要通过**全局事件拦截器**完成,因为 SQLSugar 的 `[SugarColumn]` 属性仅支持时间字段的自动填充(`InsertServerTime`/`UpdateServerTime`)。以下是具体实现方法: --- ### 一、实现步骤(以操作人ID为例) #### 1. 定义实体类 ```csharp [SugarTable("YourTable")] public class YourEntity { [SugarColumn(ColumnName = "F_LASTMODIFYUSERID")] // 映射数据库列 public string LastModifyUserId { get; set; } // 非时间字段 } ``` #### 2. 配置全局事件拦截器 在 `Program.cs` 中注册 SQLSugar 客户端并添加事件拦截: ```csharp builder.Services.AddScoped<ISqlSugarClient>(provider => { var db = new SqlSugarClient(new ConnectionConfig { ConnectionString = "YourConnectionString", DbType = DbType.SqlServer, IsAutoCloseConnection = true }); // 注册全局事件 db.Aop.DataExecuting += (oldValue, entityInfo) => { // 插入时填充创建人ID if (entityInfo.OperationType == DataFilterType.Insert) { if (entityInfo.EntityColumnInfo.PropertyName == "CreateUserId") { entityInfo.SetValue(GetCurrentUserId()); // 自动填充值 } } // 更新时填充修改人ID else if (entityInfo.OperationType == DataFilterType.Update) { if (entityInfo.EntityColumnInfo.PropertyName == "LastModifyUserId") { entityInfo.SetValue(GetCurrentUserId()); // 自动填充值 } } }; return db; }); // 获取当前用户ID(根据业务实现) private static string GetCurrentUserId() { // 示例:从Session、JWT或缓存中获取 return HttpContext.Current.User.Identity.Name; } ``` --- ### 二、关键说明 1. **事件触发时机**: - `DataExecuting`:在 SQL 执行前触发,可修改字段值 - `DataFilterType.Insert`/`Update`:区分插入和更新操作 2. **字段识别逻辑**: ```csharp if (entityInfo.EntityColumnInfo.PropertyName == "LastModifyUserId") { entityInfo.SetValue("新值"); // 动态赋值 } ``` 3. **批量操作支持**: - 事件会自动应用于所有插入/更新操作,包括 `Insertable(entityList)` 和 `Updateable(entityList)`[^2]。 --- ### 三、对比时间字段的自动填充 | **场景** | **时间字段(如 CreateTime)** | **非时间字段(如操作人ID)** | |------------------|---------------------------------------------|-----------------------------------| | **实现方式** | `[SugarColumn(InsertServerTime=true)]` [^2] | 全局事件拦截器 `Aop.DataExecuting` | | **填充类型** | 数据时间 (如 `GETDATE()`) | 自定义逻辑(如当前用户ID) | | **是否需要编码** | 声明属性即可 | 需编写事件处理逻辑 | --- ### 四、注意事项 1. **字段必须包含在操作中** 若使用 `Updateable().SetColumns(it => new { it.Name })` 仅更新部分字段,需确保目标字段(如 `LastModifyUserId`)在更新列中,否则事件不会触发。 2. **避免死循环** 在 `GetCurrentUserId()` 中不要访问数据库(可通过缓存解决),否则可能递归触发事件。 3. **多租户场景扩展** 可结合 `Aop.DataExecuting` 实现租户ID填充: ```csharp if (entityInfo.EntityColumnInfo.PropertyName == "TenantId") { entityInfo.SetValue(GetCurrentTenantId()); } ``` --- ### 五、完整示例 ```csharp // 实体类 [SugarTable("User")] public class User { [SugarColumn(IsPrimaryKey = true)] public long Id { get; set; } public string Name { get; set; } [SugarColumn(ColumnName = "F_LASTMODIFYUSERID")] public string LastModifyUserId { get; set; } // 更新时自动填充 } // 更新操作示例 var result = db.Updateable(new User { Id = 1, Name = "NewName" }) .ExecuteCommand(); // 自动生成SQL:UPDATE User SET Name='NewName', F_LASTMODIFYUSERID='user123' WHERE Id=1 ``` > 通过此方案,每次更新时 `LastModifyUserId` 会自动填充当前用户ID,无需手动赋值[^2][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值