如何将EF实体转为IQueryable实现原子递增int属性?求替代方案
问题:原子递增EF实体的Int属性
我们需要以原子方式递增实体的int属性,考虑使用EntityFramework-Plus NuGet包的Batch Update功能,它可以通过IQueryable执行更新SQL直接修改数据库值。
现有实体类:
public class Foo { public int Key1 { get; set; } public int Key2 { get; set; } public int Version { get; set; } }
希望写出这样的代码:
DbSet<Foo> dbSet; Foo foo = ...; foo.ToQuery(dbSet) .UpdateFromQuery(x => new Foo { Version = x.Version + 1 });
但缺少ToQuery方法,其签名应为:
public static IQueryable<T> ToQuery<T>(this T entity, DbSet<T> dbSet)
核心问题:
- 能否将从DbContext获取的实体转换为同一DbContext的有效IQueryable?
- 有没有更好的方法,无需自行生成SQL即可直接在数据库中递增int值?
解决方案
1. 实现ToQuery方法的可行方式
要把已跟踪的实体转成定位该实体的IQueryable,核心是利用实体的主键构建查询。EF Core可以通过提取实体的主键属性值,自动生成匹配该实体的Where条件:
public static IQueryable<T> ToQuery<T>(this T entity, DbSet<T> dbSet) where T : class { var context = dbSet.GetService<ICurrentDbContext>().Context; var entityType = context.Model.FindEntityType(typeof(T)); var primaryKey = entityType.FindPrimaryKey(); var parameter = Expression.Parameter(typeof(T), "x"); Expression predicate = null; foreach (var keyProperty in primaryKey.Properties) { var propertyAccess = Expression.Property(parameter, keyProperty.Name); var propertyValue = keyProperty.PropertyInfo.GetValue(entity); var equalsExpression = Expression.Equal(propertyAccess, Expression.Constant(propertyValue)); predicate = predicate == null ? equalsExpression : Expression.AndAlso(predicate, equalsExpression); } var query = dbSet.Where(Expression.Lambda<Func<T, bool>>(predicate, parameter)); return query; }
这个方法会自动识别实体的主键字段,构建出匹配当前实体的IQueryable,之后就能直接链式调用EF+的UpdateFromQuery实现原子递增。
2. 更直接的替代方案
其实不用转实体为IQueryable,直接通过主键构建查询更简单,还能避免反射开销:
// 假设foo是已从DbContext获取的实体 dbSet.Where(f => f.Key1 == foo.Key1 && f.Key2 == foo.Key2) .UpdateFromQuery(f => new Foo { Version = f.Version + 1 });
这种方式直接定位数据库中对应的记录,EF+会生成UPDATE ... SET Version = Version +1 WHERE Key1 = @p0 AND Key2 = @p1的原子SQL,完全满足需求,代码也更直观。
注意事项
- EF+的
UpdateFromQuery会直接生成SQL执行,不走EF的变更跟踪,所以执行后内存中的实体foo.Version不会自动更新,需要重新查询或者手动同步值。 - 数据库层面的UPDATE语句本身是原子操作,不会出现并发更新的中间状态问题。
内容的提问来源于stack exchange,提问作者Ackdari
相关产品推荐
相关产品推荐

