mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
- 增加 IUpdate.WhereCaseSource 方法,实现批量修改时的条件判断;
- 增加 FreeSql.DbContext 行级锁;
This commit is contained in:
parent
025259bb81
commit
4edfb04010
@ -50,7 +50,7 @@ namespace dbcontext_01.Controllers
|
|||||||
ctx.Songs.AddRange(adds);
|
ctx.Songs.AddRange(adds);
|
||||||
//立即执行,将自增值赋给 adds 所有元素,因为有自增类型,如果其他类型,指定传入主键值,不会立即执行
|
//立即执行,将自增值赋给 adds 所有元素,因为有自增类型,如果其他类型,指定传入主键值,不会立即执行
|
||||||
|
|
||||||
for (var a = 0; a < adds.Count; a++)
|
for (var a = 0; a < 10; a++)
|
||||||
adds[a].Title = "dkdkdkdk" + a;
|
adds[a].Title = "dkdkdkdk" + a;
|
||||||
|
|
||||||
ctx.Songs.UpdateRange(adds);
|
ctx.Songs.UpdateRange(adds);
|
||||||
@ -63,6 +63,7 @@ namespace dbcontext_01.Controllers
|
|||||||
|
|
||||||
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
||||||
ctx.Songs.Update(adds.Last());
|
ctx.Songs.Update(adds.Last());
|
||||||
|
|
||||||
//单条修改 urls 的值,进入队列
|
//单条修改 urls 的值,进入队列
|
||||||
|
|
||||||
//throw new Exception("回滚");
|
//throw new Exception("回滚");
|
||||||
|
@ -25,6 +25,9 @@ namespace dbcontext_01 {
|
|||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<Tag> Tags { get; set; }
|
public virtual ICollection<Tag> Tags { get; set; }
|
||||||
|
|
||||||
|
[Version]
|
||||||
|
public long versionRow { get; set; }
|
||||||
}
|
}
|
||||||
public class Song_tag {
|
public class Song_tag {
|
||||||
public int Song_id { get; set; }
|
public int Song_id { get; set; }
|
||||||
|
@ -25,6 +25,7 @@ namespace dbcontext_01
|
|||||||
.UseLogger(loggerFactory.CreateLogger<IFreeSql>())
|
.UseLogger(loggerFactory.CreateLogger<IFreeSql>())
|
||||||
.UseAutoSyncStructure(true)
|
.UseAutoSyncStructure(true)
|
||||||
.UseLazyLoading(true)
|
.UseLazyLoading(true)
|
||||||
|
.UseNoneCommandParameter(true)
|
||||||
|
|
||||||
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText),
|
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText),
|
||||||
(cmd, log) => Trace.WriteLine(log)
|
(cmd, log) => Trace.WriteLine(log)
|
||||||
|
8
FreeSql.DbContext/DataAnnotations/VersionAttribute.cs
Normal file
8
FreeSql.DbContext/DataAnnotations/VersionAttribute.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public class VersionAttribute : Attribute {
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ namespace FreeSql {
|
|||||||
public class DbContextOptionsBuilder {
|
public class DbContextOptionsBuilder {
|
||||||
|
|
||||||
internal IFreeSql _fsql;
|
internal IFreeSql _fsql;
|
||||||
|
|
||||||
public DbContextOptionsBuilder UseFreeSql(IFreeSql orm) {
|
public DbContextOptionsBuilder UseFreeSql(IFreeSql orm) {
|
||||||
_fsql = orm;
|
_fsql = orm;
|
||||||
return this;
|
return this;
|
@ -15,32 +15,50 @@ using FreeSql.Extensions;
|
|||||||
namespace FreeSql {
|
namespace FreeSql {
|
||||||
public abstract partial class DbSet<TEntity> where TEntity : class {
|
public abstract partial class DbSet<TEntity> where TEntity : class {
|
||||||
|
|
||||||
protected DbContext _ctx;
|
internal DbContext _ctx;
|
||||||
IFreeSql _fsql => _ctx._fsql;
|
IFreeSql _fsql => _ctx._fsql;
|
||||||
|
|
||||||
protected ISelect<TEntity> OrmSelect(object dywhere) {
|
ISelect<TEntity> OrmSelect(object dywhere) {
|
||||||
_ctx.ExecCommand(); //查询前先提交,否则会出脏读
|
_ctx.ExecCommand(); //查询前先提交,否则会出脏读
|
||||||
return _fsql.Select<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction(false)).TrackToList(TrackToList);
|
return _fsql.Select<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction(false)).TrackToList(TrackToList);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IInsert<TEntity> OrmInsert() => _fsql.Insert<TEntity>().WithTransaction(_ctx.GetOrBeginTransaction());
|
IInsert<TEntity> OrmInsert() => _fsql.Insert<TEntity>().WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
protected IInsert<TEntity> OrmInsert(TEntity data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
IInsert<TEntity> OrmInsert(TEntity data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
protected IInsert<TEntity> OrmInsert(TEntity[] data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
IInsert<TEntity> OrmInsert(TEntity[] data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
protected IInsert<TEntity> OrmInsert(IEnumerable<TEntity> data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
IInsert<TEntity> OrmInsert(IEnumerable<TEntity> data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
|
|
||||||
protected IUpdate<TEntity> OrmUpdate(object dywhere) => _fsql.Update<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
|
IUpdate<TEntity> OrmUpdate(object dywhere) => _fsql.Update<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
protected IDelete<TEntity> OrmDelete(object dywhere) => _fsql.Delete<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
|
IDelete<TEntity> OrmDelete(object dywhere) => _fsql.Delete<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
|
||||||
|
|
||||||
public ISelect<TEntity> Select => this.OrmSelect(null);
|
public ISelect<TEntity> Select => this.OrmSelect(null);
|
||||||
public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).Where(exp);
|
public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).Where(exp);
|
||||||
public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).WhereIf(condition, exp);
|
public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).WhereIf(condition, exp);
|
||||||
|
|
||||||
protected Dictionary<string, EntityState> _states = new Dictionary<string, EntityState>();
|
Dictionary<string, EntityState> _states = new Dictionary<string, EntityState>();
|
||||||
TableInfo _tablePriv;
|
TableInfo _tablePriv;
|
||||||
protected TableInfo _table => _tablePriv ?? (_tablePriv = _fsql.CodeFirst.GetTableByEntity(_entityType));
|
TableInfo _table => _tablePriv ?? (_tablePriv = _fsql.CodeFirst.GetTableByEntity(_entityType));
|
||||||
ColumnInfo[] _tableIdentitysPriv;
|
ColumnInfo[] _tableIdentitysPriv;
|
||||||
protected ColumnInfo[] _tableIdentitys => _tableIdentitysPriv ?? (_tableIdentitysPriv = _table.Primarys.Where(a => a.Attribute.IsIdentity).ToArray());
|
ColumnInfo[] _tableIdentitys => _tableIdentitysPriv ?? (_tableIdentitysPriv = _table.Primarys.Where(a => a.Attribute.IsIdentity).ToArray());
|
||||||
protected Type _entityType = typeof(TEntity);
|
Type _entityType = typeof(TEntity);
|
||||||
|
|
||||||
|
bool _versionColumnPrivPrivIsInit = false;
|
||||||
|
ColumnInfo _versionColumnPriv;
|
||||||
|
ColumnInfo _versionColumn {
|
||||||
|
get {
|
||||||
|
if (_versionColumnPrivPrivIsInit == false) {
|
||||||
|
var vc = _table.Properties.Where(a => _table.ColumnsByCs.ContainsKey(a.Key) && a.Value.GetCustomAttributes(typeof(VersionAttribute), false).Any());
|
||||||
|
if (vc.Any()) {
|
||||||
|
var col = _table.ColumnsByCs[vc.Last().Key];
|
||||||
|
if (col.CsType.IsNullableType() || col.CsType.IsNumberType() == false)
|
||||||
|
throw new Exception($"属性{col.CsName} 被标注为行级锁(Version),但其必须为数字类型,并且不可为 Nullable");
|
||||||
|
_versionColumnPriv = col;
|
||||||
|
}
|
||||||
|
_versionColumnPrivPrivIsInit = true;
|
||||||
|
}
|
||||||
|
return _versionColumnPriv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class EntityState {
|
public class EntityState {
|
||||||
public EntityState(TEntity value, string key) {
|
public EntityState(TEntity value, string key) {
|
||||||
@ -54,20 +72,20 @@ namespace FreeSql {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
protected EntityState CreateEntityState(TEntity data) {
|
EntityState CreateEntityState(TEntity data) {
|
||||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||||
var key = _fsql.GetEntityKeyString(data);
|
var key = _fsql.GetEntityKeyString(data);
|
||||||
var state = new EntityState(Activator.CreateInstance<TEntity>(), key);
|
var state = new EntityState(Activator.CreateInstance<TEntity>(), key);
|
||||||
_fsql.MapEntityValue(data, state.Value);
|
_fsql.MapEntityValue(data, state.Value);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
protected bool ExistsInStates(TEntity data) {
|
bool ExistsInStates(TEntity data) {
|
||||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||||
var key = _fsql.GetEntityKeyString(data);
|
var key = _fsql.GetEntityKeyString(data);
|
||||||
if (string.IsNullOrEmpty(key)) return false;
|
if (string.IsNullOrEmpty(key)) return false;
|
||||||
return _states.ContainsKey(key);
|
return _states.ContainsKey(key);
|
||||||
}
|
}
|
||||||
protected bool CanAdd(TEntity[] data, bool isThrow) {
|
bool CanAdd(TEntity[] data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -75,7 +93,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanAdd(IEnumerable<TEntity> data, bool isThrow) {
|
bool CanAdd(IEnumerable<TEntity> data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -83,7 +101,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanAdd(TEntity data, bool isThrow) {
|
bool CanAdd(TEntity data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -117,7 +135,7 @@ namespace FreeSql {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool CanUpdate(TEntity[] data, bool isThrow) {
|
bool CanUpdate(TEntity[] data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -125,7 +143,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanUpdate(IEnumerable<TEntity> data, bool isThrow) {
|
bool CanUpdate(IEnumerable<TEntity> data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -133,7 +151,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanUpdate(TEntity data, bool isThrow) {
|
bool CanUpdate(TEntity data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -154,7 +172,7 @@ namespace FreeSql {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool CanRemove(TEntity[] data, bool isThrow) {
|
bool CanRemove(TEntity[] data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -162,7 +180,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanRemove(IEnumerable<TEntity> data, bool isThrow) {
|
bool CanRemove(IEnumerable<TEntity> data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
||||||
@ -170,7 +188,7 @@ namespace FreeSql {
|
|||||||
foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
|
foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected bool CanRemove(TEntity data, bool isThrow) {
|
bool CanRemove(TEntity data, bool isThrow) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
if (isThrow) throw new ArgumentNullException(nameof(data));
|
if (isThrow) throw new ArgumentNullException(nameof(data));
|
||||||
return false;
|
return false;
|
@ -148,26 +148,68 @@ namespace FreeSql {
|
|||||||
|
|
||||||
var cuig1 = _fsql.CompareEntityValueReturnColumns(uplst1.Value, lstval1.Value, true);
|
var cuig1 = _fsql.CompareEntityValueReturnColumns(uplst1.Value, lstval1.Value, true);
|
||||||
var cuig2 = uplst2 != null ? _fsql.CompareEntityValueReturnColumns(uplst2.Value, lstval2.Value, true) : null;
|
var cuig2 = uplst2 != null ? _fsql.CompareEntityValueReturnColumns(uplst2.Value, lstval2.Value, true) : null;
|
||||||
|
|
||||||
|
List<EntityState> data = null;
|
||||||
|
string[] cuig = null;
|
||||||
if (uplst2 != null && string.Compare(string.Join(",", cuig1), string.Join(",", cuig2)) != 0) {
|
if (uplst2 != null && string.Compare(string.Join(",", cuig1), string.Join(",", cuig2)) != 0) {
|
||||||
//最后一个不保存
|
//最后一个不保存
|
||||||
var data = ups.ToList();
|
data = ups.ToList();
|
||||||
data.RemoveAt(ups.Length - 1);
|
data.RemoveAt(ups.Length - 1);
|
||||||
var affrows = this.OrmUpdate(null).SetSource(data.Select(a => a.Value)).IgnoreColumns(cuig2).ExecuteAffrows();
|
cuig = cuig2;
|
||||||
|
} else if (isLiveUpdate) {
|
||||||
|
//立即保存
|
||||||
|
data = ups.ToList();
|
||||||
|
cuig = cuig1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data?.Count > 0) {
|
||||||
|
|
||||||
|
if (cuig.Length == _table.Columns.Count)
|
||||||
|
return data.Count;
|
||||||
|
|
||||||
|
var updateSource = data.Select(a => a.Value).ToArray();
|
||||||
|
var update = this.OrmUpdate(null).SetSource(updateSource);
|
||||||
|
|
||||||
|
var isWhereVersion = false;
|
||||||
|
if (_versionColumn != null) {
|
||||||
|
if (cuig.Contains(_versionColumn.CsName)) {
|
||||||
|
var parm1Exp = Expression.Parameter(_entityType, "a");
|
||||||
|
var lambdExp = Expression.Lambda(
|
||||||
|
typeof(Func<,>).MakeGenericType(_entityType, _versionColumn.CsType),
|
||||||
|
Expression.Add(
|
||||||
|
Expression.MakeMemberAccess(parm1Exp, _table.Properties[_versionColumn.CsName]),
|
||||||
|
Expression.Convert(Expression.Constant(1), _versionColumn.CsType)
|
||||||
|
),
|
||||||
|
parm1Exp
|
||||||
|
);
|
||||||
|
update.AppendEntityUpdateSetWithColumn(_versionColumn.CsType, lambdExp);
|
||||||
|
isWhereVersion = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update.IgnoreColumns(cuig);
|
||||||
|
|
||||||
|
if (isWhereVersion)
|
||||||
|
update.WhereCaseSource(_versionColumn.CsName, sqlval => sqlval);
|
||||||
|
|
||||||
|
var affrows = update.ExecuteAffrows();
|
||||||
|
|
||||||
|
if (affrows != updateSource.Length) {
|
||||||
|
if (_versionColumn != null)
|
||||||
|
throw new Exception("数据未更新,其中的记录可能不存在,或者【行级乐观锁】版本过旧");
|
||||||
|
throw new Exception("数据未更新,其中的记录可能不存在");
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var newval in data) {
|
foreach (var newval in data) {
|
||||||
|
|
||||||
|
if (isWhereVersion)
|
||||||
|
_fsql.SetEntityIncrByWithPropertyName(newval.Value, _versionColumn.CsName, 1);
|
||||||
|
|
||||||
if (_states.TryGetValue(newval.Key, out var tryold))
|
if (_states.TryGetValue(newval.Key, out var tryold))
|
||||||
_fsql.MapEntityValue(newval.Value, tryold.Value);
|
_fsql.MapEntityValue(newval.Value, tryold.Value);
|
||||||
}
|
}
|
||||||
return affrows;
|
return affrows;
|
||||||
} else if (isLiveUpdate) {
|
|
||||||
//立即保存
|
|
||||||
var data = ups;
|
|
||||||
var affrows = this.OrmUpdate(null).SetSource(data.Select(a => a.Value)).IgnoreColumns(cuig1).ExecuteAffrows();
|
|
||||||
foreach (var newval in data) {
|
|
||||||
if (_states.TryGetValue(newval.Key, out var tryold))
|
|
||||||
_fsql.MapEntityValue(newval.Value, tryold.Value);
|
|
||||||
}
|
|
||||||
return Math.Min(ups.Length, affrows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//等待下次对比再保存
|
//等待下次对比再保存
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -303,5 +303,63 @@ namespace FreeSql.Extensions {
|
|||||||
});
|
});
|
||||||
return func(up, oldval, isEqual);
|
return func(up, oldval, isEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, string, int>>> _dicSetEntityIncrByWithPropertyName = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, string, int>>>();
|
||||||
|
/// <summary>
|
||||||
|
/// 设置实体中某属性的数值增加指定的值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
|
/// <param name="orm"></param>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <param name="idtval"></param>
|
||||||
|
public static void SetEntityIncrByWithPropertyName<TEntity>(this IFreeSql orm, TEntity item, string propertyName, int incrBy) {
|
||||||
|
var func = _dicSetEntityIncrByWithPropertyName.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, Action<object, string, int>>()).GetOrAdd(typeof(TEntity), t => {
|
||||||
|
var _table = orm.CodeFirst.GetTableByEntity(t);
|
||||||
|
var parm1 = Expression.Parameter(typeof(object));
|
||||||
|
var parm2 = Expression.Parameter(typeof(string));
|
||||||
|
var parm3 = Expression.Parameter(typeof(int));
|
||||||
|
var var1Parm = Expression.Variable(t);
|
||||||
|
var exps = new List<Expression>(new Expression[] {
|
||||||
|
Expression.Assign(var1Parm, Expression.TypeAs(parm1, t))
|
||||||
|
});
|
||||||
|
if (_table.Properties.ContainsKey(propertyName)) {
|
||||||
|
var prop = _table.Properties[propertyName];
|
||||||
|
exps.Add(
|
||||||
|
Expression.Assign(
|
||||||
|
Expression.MakeMemberAccess(var1Parm, prop),
|
||||||
|
Expression.Add(
|
||||||
|
Expression.MakeMemberAccess(var1Parm, prop),
|
||||||
|
Expression.Convert(
|
||||||
|
FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(prop.PropertyType, Expression.Convert(parm3, typeof(object))),
|
||||||
|
prop.PropertyType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Expression.Lambda<Action<object, string, int>>(Expression.Block(new[] { var1Parm }, exps), new[] { parm1, parm2, parm3 }).Compile();
|
||||||
|
});
|
||||||
|
func(item, propertyName, incrBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ConcurrentDictionary<Type, MethodInfo[]> _dicAppendEntityUpdateSetWithColumnMethods = new ConcurrentDictionary<Type, MethodInfo[]>();
|
||||||
|
static ConcurrentDictionary<Type, ConcurrentDictionary<Type, MethodInfo>> _dicAppendEntityUpdateSetWithColumnMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, MethodInfo>>();
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存执行 IUpdate.Set
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
|
/// <param name="update"></param>
|
||||||
|
/// <param name="columnType"></param>
|
||||||
|
/// <param name="setExp"></param>
|
||||||
|
public static void AppendEntityUpdateSetWithColumn<TEntity>(this IUpdate<TEntity> update, Type columnType, LambdaExpression setExp) where TEntity : class {
|
||||||
|
|
||||||
|
var setMethod = _dicAppendEntityUpdateSetWithColumnMethod.GetOrAdd(typeof(IUpdate<TEntity>), uptp => new ConcurrentDictionary<Type, MethodInfo>()).GetOrAdd(columnType, coltp => {
|
||||||
|
var allMethods = _dicAppendEntityUpdateSetWithColumnMethods.GetOrAdd(typeof(IUpdate<TEntity>), uptp => uptp.GetMethods());
|
||||||
|
return allMethods.Where(a => a.Name == "Set" && a.IsGenericMethod && a.GetParameters().Length == 1 && a.GetGenericArguments().First().Name == "TMember").FirstOrDefault()
|
||||||
|
.MakeGenericMethod(columnType);
|
||||||
|
});
|
||||||
|
|
||||||
|
setMethod.Invoke(update, new object[] { setExp });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Version>0.3.216</Version>
|
<Version>0.3.27</Version>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Authors>YeXiangQin</Authors>
|
<Authors>YeXiangQin</Authors>
|
||||||
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Version>0.3.26</Version>
|
<Version>0.3.27</Version>
|
||||||
<Authors>YeXiangQin</Authors>
|
<Authors>YeXiangQin</Authors>
|
||||||
<Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table.</Description>
|
<Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table.</Description>
|
||||||
<PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/Repository</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/Repository</PackageProjectUrl>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Version>0.3.26</Version>
|
<Version>0.3.27</Version>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Authors>YeXiangQin</Authors>
|
<Authors>YeXiangQin</Authors>
|
||||||
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
||||||
|
@ -101,6 +101,13 @@ namespace FreeSql {
|
|||||||
/// <param name="notExists">不存在</param>
|
/// <param name="notExists">不存在</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class;
|
IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 用于批量修改时,生成 where dbName = case when id = 1 then v1 end 的条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="CsName">属性名</param>
|
||||||
|
/// <param name="thenValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> WhereCaseSource(string CsName, Func<string, string> thenValue);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名;
|
/// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名;
|
||||||
|
@ -20,6 +20,7 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
protected Func<string, string> _tableRule;
|
protected Func<string, string> _tableRule;
|
||||||
protected StringBuilder _where = new StringBuilder();
|
protected StringBuilder _where = new StringBuilder();
|
||||||
protected StringBuilder _set = new StringBuilder();
|
protected StringBuilder _set = new StringBuilder();
|
||||||
|
protected StringBuilder _setIncr = new StringBuilder();
|
||||||
protected List<DbParameter> _params = new List<DbParameter>();
|
protected List<DbParameter> _params = new List<DbParameter>();
|
||||||
protected List<DbParameter> _paramsSource = new List<DbParameter>();
|
protected List<DbParameter> _paramsSource = new List<DbParameter>();
|
||||||
protected bool _noneParameter;
|
protected bool _noneParameter;
|
||||||
@ -40,6 +41,7 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
_ignore.Clear();
|
_ignore.Clear();
|
||||||
_where.Clear();
|
_where.Clear();
|
||||||
_set.Clear();
|
_set.Clear();
|
||||||
|
_setIncr.Clear();
|
||||||
_params.Clear();
|
_params.Clear();
|
||||||
_paramsSource.Clear();
|
_paramsSource.Clear();
|
||||||
}
|
}
|
||||||
@ -117,7 +119,7 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
expt = expt.Replace(replname, _commonUtils.IsNull(replname, _commonUtils.FormatSql("{0}", replval)));
|
expt = expt.Replace(replname, _commonUtils.IsNull(replname, _commonUtils.FormatSql("{0}", replval)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_set.Append(", ").Append(_commonUtils.QuoteSqlName(cols.First().Column.Attribute.Name)).Append(" = ").Append(expt);
|
_setIncr.Append(", ").Append(_commonUtils.QuoteSqlName(cols.First().Column.Attribute.Name)).Append(" = ").Append(expt);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public IUpdate<T1> SetRaw(string sql, object parms = null) {
|
public IUpdate<T1> SetRaw(string sql, object parms = null) {
|
||||||
@ -142,6 +144,45 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
public IUpdate<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
public IUpdate<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
||||||
public IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
public IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
||||||
|
|
||||||
|
public IUpdate<T1> WhereCaseSource(string CsName, Func<string, string> thenValue) {
|
||||||
|
if (_source.Any() == false) return this;
|
||||||
|
if (_table.ColumnsByCs.ContainsKey(CsName) == false) throw new Exception($"找不到 {CsName} 对应的列");
|
||||||
|
if (thenValue == null) throw new ArgumentNullException("thenValue 参数不可为 null");
|
||||||
|
|
||||||
|
if (_source.Count == 0) return this;
|
||||||
|
if (_source.Count == 1) {
|
||||||
|
|
||||||
|
var col = _table.ColumnsByCs[CsName];
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ");
|
||||||
|
var value = _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(_source.First()) : DBNull.Value;
|
||||||
|
sb.Append(thenValue(_commonUtils.GetNoneParamaterSqlValue(_paramsSource, col.CsType, value)));
|
||||||
|
|
||||||
|
return this.Where(sb.ToString());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var caseWhen = new StringBuilder();
|
||||||
|
caseWhen.Append("CASE ");
|
||||||
|
ToSqlCase(caseWhen, _table.Primarys);
|
||||||
|
var cw = caseWhen.ToString();
|
||||||
|
|
||||||
|
var col = _table.ColumnsByCs[CsName];
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(cw);
|
||||||
|
foreach (var d in _source) {
|
||||||
|
sb.Append(" \r\nWHEN ");
|
||||||
|
ToSqlWhen(sb, _table.Primarys, d);
|
||||||
|
sb.Append(" THEN ");
|
||||||
|
var value = _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value;
|
||||||
|
sb.Append(thenValue(_commonUtils.GetNoneParamaterSqlValue(_paramsSource, col.CsType, value)));
|
||||||
|
}
|
||||||
|
sb.Append(" END");
|
||||||
|
|
||||||
|
return this.Where(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys);
|
protected abstract void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys);
|
||||||
protected abstract void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d);
|
protected abstract void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d);
|
||||||
|
|
||||||
@ -227,6 +268,7 @@ namespace FreeSql.Internal.CommonProvider {
|
|||||||
} else
|
} else
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
sb.Append(_setIncr.ToString());
|
||||||
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user