如何配置OData中的Delta<TEntity>以修改其UpdatableProperties属性?
OData Patch调用前过滤Delta不可更新属性的实现方案
以下是三种常用的落地实现方案,可根据自身业务场景选择:
方案1:自定义ActionFilter全局拦截处理
适合需要批量处理所有Patch接口的场景,无需侵入业务代码:
public class DeltaReservedPropertiesFilter : IActionFilter { // 复用你定义的禁止更新字段列表 private readonly List<string> _reservedProperties = new List<string>() { "ObjectId", "IsDeleted", "DeleterUserId", "DeletionTime", "LastModificationTime", "LastModifierUserId", "CreationTime", "CreatorUserId", "CreatorUser", "TenantId" }; public void OnActionExecuting(ActionExecutingContext context) { // 仅处理Patch请求 if (context.HttpContext.Request.Method != HttpMethod.Patch.Method) return; // 匹配参数中的Delta对象 var deltaParam = context.ActionArguments.FirstOrDefault(arg => arg.Value?.GetType().IsGenericType == true && arg.Value.GetType().GetGenericTypeDefinition() == typeof(Delta<>)); if (deltaParam.Value == null) return; // 反射获取UpdatableProperties集合并移除保留字段 var updatableProps = deltaParam.Value.GetType().GetProperty("UpdatableProperties")?.GetValue(deltaParam.Value) as ICollection<string>; if (updatableProps == null) return; foreach (var prop in _reservedProperties) { updatableProps.Remove(prop); } } public void OnActionExecuted(ActionExecutedContext context) {} }
在Program.cs中注册Filter即可全局生效:
builder.Services.AddControllers(options => { options.Filters.Add<DeltaReservedPropertiesFilter>(); });
方案2:封装Delta扩展方法按需调用
适合仅部分接口需要做字段过滤的场景,灵活性更高:
public static class DeltaExtensions { private static readonly List<string> ReservedPropertiesName = new List<string>() { "ObjectId", "IsDeleted", "DeleterUserId", "DeletionTime", "LastModificationTime", "LastModifierUserId", "CreationTime", "CreatorUserId", "CreatorUser", "TenantId" }; public static void RemoveReservedProperties<T>(this Delta<T> delta) where T : class { // 移除禁止更新的属性配置 foreach (var prop in ReservedPropertiesName) { delta.UpdatableProperties.Remove(prop); } // 清理客户端已经提交的保留字段值,避免误写入 var changedProps = delta.GetChangedPropertyNames().ToList(); foreach (var prop in changedProps.Intersect(ReservedPropertiesName)) { delta.TryUnsetPropertyValue(prop); } } }
在Patch方法开头直接调用即可:
public IActionResult Patch([FromODataUri] int key, Delta<MyEntity> delta) { delta.RemoveReservedProperties(); // 后续原有业务逻辑 }
方案3:基于特性自动识别不可更新字段
避免硬编码属性名,可直接在模型上标记禁止更新的属性:
首先定义标记特性:
[AttributeUsage(AttributeTargets.Property)] public class NonUpdatableAttribute : Attribute { }
在实体模型上标记禁止更新的字段:
public class MyEntity { [NonUpdatable] public string ObjectId { get; set; } [NonUpdatable] public bool IsDeleted { get; set; } // 其他字段... }
在过滤逻辑中动态收集需要移除的字段:
var nonUpdatableProps = typeof(T).GetProperties() .Where(p => p.GetCustomAttribute<NonUpdatableAttribute>() != null) .Select(p => p.Name) .ToList(); // 后续执行移除操作即可
注意事项
- 移除
UpdatableProperties中的字段后,Delta后续执行Patch、TrySetPropertyValue等操作时都会自动忽略这些字段,不会修改实体对应的值 - 如果需要支持不同角色的可更新字段差异,可以在过滤逻辑中加入当前用户的权限校验,动态生成需要移除的属性列表
- 建议同时添加已提交保留字段的清理逻辑,避免客户端提交的非法值被误写入数据库
内容的提问来源于stack exchange,提问作者Gaby Jawhar
相关产品推荐
相关产品推荐

