mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 20:38:16 +08:00
- 增加 [Table(AsTable = xx)] 分表特性,完成分表插入/删除;
This commit is contained in:
@ -95,7 +95,9 @@ namespace FreeSql.Internal.CommonProvider
|
||||
{
|
||||
if (objects == null) return;
|
||||
var syncObjects = objects.Where(a => a.entityType != null && a.entityType != typeof(object) && _dicSycedGetOrAdd(a.entityType).ContainsKey(GetTableNameLowerOrUpper(a.tableName)) == false && GetTableByEntity(a.entityType)?.DisableSyncStructure == false)
|
||||
.Select(a => new TypeAndName(a.entityType, GetTableNameLowerOrUpper(a.tableName))).ToArray();
|
||||
.Select(a => new TypeAndName(a.entityType, GetTableNameLowerOrUpper(a.tableName)))
|
||||
.Where(a => !(string.IsNullOrEmpty(a.tableName) == true && GetTableByEntity(a.entityType)?.AsTableImpl != null))
|
||||
.ToArray();
|
||||
if (syncObjects.Any() == false) return;
|
||||
var before = new Aop.SyncStructureBeforeEventArgs(syncObjects.Select(a => a.entityType).ToArray());
|
||||
_orm.Aop.SyncStructureBeforeHandler?.Invoke(this, before);
|
||||
|
@ -10,8 +10,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider
|
||||
{
|
||||
|
||||
public abstract partial class DeleteProvider<T1> : IDelete<T1>
|
||||
public abstract partial class DeleteProvider
|
||||
{
|
||||
public IFreeSql _orm;
|
||||
public CommonUtils _commonUtils;
|
||||
@ -26,7 +25,10 @@ namespace FreeSql.Internal.CommonProvider
|
||||
public DbConnection _connection;
|
||||
public int _commandTimeout = 0;
|
||||
public Action<StringBuilder> _interceptSql;
|
||||
}
|
||||
|
||||
public abstract partial class DeleteProvider<T1> : DeleteProvider, IDelete<T1>
|
||||
{
|
||||
public DeleteProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||
{
|
||||
_orm = orm;
|
||||
@ -66,28 +68,32 @@ namespace FreeSql.Internal.CommonProvider
|
||||
|
||||
public int ExecuteAffrows()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
var dbParms = _params.ToArray();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
var affrows = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
DbParameter[] dbParms = null;
|
||||
ToSqlFetch(sb =>
|
||||
{
|
||||
affrows = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
this.ClearData();
|
||||
if (dbParms == null) dbParms = _params.ToArray();
|
||||
var sql = sb.ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
affrows += _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
});
|
||||
if (dbParms != null) this.ClearData();
|
||||
return affrows;
|
||||
}
|
||||
public abstract List<T1> ExecuteDeleted();
|
||||
@ -165,16 +171,77 @@ namespace FreeSql.Internal.CommonProvider
|
||||
public virtual string ToSql()
|
||||
{
|
||||
if (_whereTimes <= 0) return null;
|
||||
var sb = new StringBuilder().Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" WHERE ").Append(_where);
|
||||
var sb = new StringBuilder();
|
||||
ToSqlFetch(sql =>
|
||||
{
|
||||
sb.Append(sql).Append("\r\n\r\n;\r\n\r\n");
|
||||
});
|
||||
if (sb.Length > 0) sb.Remove(sb.Length - 9, 9);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void ToSqlFetch(Action<StringBuilder> fetch)
|
||||
{
|
||||
if (_whereTimes <= 0) return;
|
||||
var newwhere = new StringBuilder().Append(" WHERE ").Append(_where);
|
||||
|
||||
if (_whereGlobalFilter.Any())
|
||||
{
|
||||
var globalFilterCondi = _commonExpression.GetWhereCascadeSql(new SelectTableInfo { Table = _table }, _whereGlobalFilter, false);
|
||||
if (string.IsNullOrEmpty(globalFilterCondi) == false)
|
||||
sb.Append(" AND ").Append(globalFilterCondi);
|
||||
newwhere.Append(" AND ").Append(globalFilterCondi);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (_table.AsTableImpl != null)
|
||||
{
|
||||
var names = _table.AsTableImpl.GetTableNamesBySqlWhere(newwhere.ToString(), _params, _table, _commonUtils);
|
||||
foreach (var name in names)
|
||||
{
|
||||
_tableRule = old => name;
|
||||
sb.Clear().Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(newwhere);
|
||||
_interceptSql?.Invoke(sb);
|
||||
fetch(sb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sb.Insert(0, _commonUtils.QuoteSqlName(TableRuleInvoke())).Insert(0, "DELETE FROM ");
|
||||
_interceptSql?.Invoke(sb);
|
||||
return sb.ToString();
|
||||
fetch(sb);
|
||||
}
|
||||
#if net40
|
||||
#else
|
||||
async public Task ToSqlFetchAsync(Func<StringBuilder, Task> fetchAsync)
|
||||
{
|
||||
if (_whereTimes <= 0) return;
|
||||
var newwhere = new StringBuilder().Append(" WHERE ").Append(_where);
|
||||
|
||||
if (_whereGlobalFilter.Any())
|
||||
{
|
||||
var globalFilterCondi = _commonExpression.GetWhereCascadeSql(new SelectTableInfo { Table = _table }, _whereGlobalFilter, false);
|
||||
if (string.IsNullOrEmpty(globalFilterCondi) == false)
|
||||
newwhere.Append(" AND ").Append(globalFilterCondi);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (_table.AsTableImpl != null)
|
||||
{
|
||||
var names = _table.AsTableImpl.GetTableNamesBySqlWhere(newwhere.ToString(), _params, _table, _commonUtils);
|
||||
foreach (var name in names)
|
||||
{
|
||||
_tableRule = old => name;
|
||||
sb.Clear().Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(newwhere);
|
||||
_interceptSql?.Invoke(sb);
|
||||
await fetchAsync(sb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sb.Insert(0, _commonUtils.QuoteSqlName(TableRuleInvoke())).Insert(0, "DELETE FROM ");
|
||||
_interceptSql?.Invoke(sb);
|
||||
await fetchAsync(sb);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -16,28 +16,32 @@ namespace FreeSql.Internal.CommonProvider
|
||||
#else
|
||||
async public Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
var dbParms = _params.ToArray();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
var affrows = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
DbParameter[] dbParms = null;
|
||||
await ToSqlFetchAsync(async sb =>
|
||||
{
|
||||
affrows = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
this.ClearData();
|
||||
if (dbParms == null) dbParms = _params.ToArray();
|
||||
var sql = sb.ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
affrows += await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
});
|
||||
if (dbParms != null) this.ClearData();
|
||||
return affrows;
|
||||
}
|
||||
public abstract Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default);
|
||||
|
@ -14,12 +14,11 @@ using System.Collections;
|
||||
namespace FreeSql.Internal.CommonProvider
|
||||
{
|
||||
|
||||
public abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class
|
||||
public abstract partial class InsertProvider
|
||||
{
|
||||
public IFreeSql _orm;
|
||||
public CommonUtils _commonUtils;
|
||||
public CommonExpression _commonExpression;
|
||||
public List<T1> _source = new List<T1>();
|
||||
public Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||
public Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||
public TableInfo _table;
|
||||
@ -28,11 +27,17 @@ namespace FreeSql.Internal.CommonProvider
|
||||
public bool _noneParameter, _insertIdentity;
|
||||
public int _batchValuesLimit, _batchParameterLimit;
|
||||
public bool _batchAutoTransaction = true;
|
||||
public Action<BatchProgressStatus<T1>> _batchProgress;
|
||||
public DbParameter[] _params;
|
||||
public DbTransaction _transaction;
|
||||
public DbConnection _connection;
|
||||
public int _commandTimeout = 0;
|
||||
}
|
||||
|
||||
public abstract partial class InsertProvider<T1> : InsertProvider, IInsert<T1> where T1 : class
|
||||
{
|
||||
public List<T1> _source = new List<T1>();
|
||||
internal List<T1> _sourceOld;
|
||||
public Action<BatchProgressStatus<T1>> _batchProgress;
|
||||
|
||||
public InsertProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
{
|
||||
@ -43,6 +48,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
_noneParameter = _orm.CodeFirst.IsNoneCommandParameter;
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure && typeof(T1) != typeof(object)) _orm.CodeFirst.SyncStructure<T1>();
|
||||
IgnoreCanInsert();
|
||||
_sourceOld = _source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -62,6 +68,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
_batchProgress = null;
|
||||
_insertIdentity = false;
|
||||
_source.Clear();
|
||||
_sourceOld = _source;
|
||||
_ignore.Clear();
|
||||
_auditValueChangedDict.Clear();
|
||||
_params = null;
|
||||
@ -189,7 +196,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
}
|
||||
|
||||
#region 参数化数据限制,或values数量限制
|
||||
protected List<T1>[] SplitSource(int valuesLimit, int parameterLimit)
|
||||
protected List<T1>[] SplitSource(int valuesLimit, int parameterLimit, bool isAsTableSplited = false)
|
||||
{
|
||||
valuesLimit = valuesLimit - 1;
|
||||
parameterLimit = parameterLimit - 1;
|
||||
@ -198,6 +205,28 @@ namespace FreeSql.Internal.CommonProvider
|
||||
if (_source == null || _source.Any() == false) return new List<T1>[0];
|
||||
if (_source.Count == 1) return new[] { _source };
|
||||
|
||||
if (_table.AsTableImpl != null && isAsTableSplited == false)
|
||||
{
|
||||
var atarr = _source.Select(a => new
|
||||
{
|
||||
item = a,
|
||||
splitKey = _table.AsTableImpl.GetTableNameByColumnValue(_table.AsTableColumn.GetValue(a), true)
|
||||
}).GroupBy(a => a.splitKey, a => a.item).ToArray();
|
||||
if (atarr.Length > 1)
|
||||
{
|
||||
var oldSource = _source;
|
||||
var arrret = new List<List<T1>>();
|
||||
foreach (var item in atarr)
|
||||
{
|
||||
_source = item.ToList();
|
||||
var itemret = SplitSource(valuesLimit + 1, parameterLimit + 1, true);
|
||||
arrret.AddRange(itemret);
|
||||
}
|
||||
_source = oldSource;
|
||||
return arrret.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
var takeMax = valuesLimit;
|
||||
if (_noneParameter == false)
|
||||
{
|
||||
@ -510,8 +539,8 @@ namespace FreeSql.Internal.CommonProvider
|
||||
protected string TableRuleInvoke()
|
||||
{
|
||||
var tbname = _table?.DbName ?? "";
|
||||
if (_tableRule == null) return tbname;
|
||||
var newname = _tableRule(tbname);
|
||||
if (_tableRule == null && _table.AsTableImpl == null) return tbname;
|
||||
var newname = _table.AsTableImpl?.GetTableNameByColumnValue(_source.Any() ? _table.AsTableColumn.GetValue(_source.FirstOrDefault()) : DateTime.Now) ?? _tableRule(tbname);
|
||||
if (newname == tbname) return tbname;
|
||||
if (string.IsNullOrEmpty(newname)) return tbname;
|
||||
if (_orm.CodeFirst.IsSyncStructureToLower) newname = newname.ToLower();
|
||||
@ -540,14 +569,38 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual string ToSql() => ToSqlValuesOrSelectUnionAllExtension102(true, null, null);
|
||||
public virtual string ToSql() => ToSqlValuesOrSelectUnionAllExtension103(true, null, null, false);
|
||||
|
||||
public string ToSqlValuesOrSelectUnionAll(bool isValues = true) => ToSqlValuesOrSelectUnionAllExtension102(isValues, null, null);
|
||||
public string ToSqlValuesOrSelectUnionAllExtension101(bool isValues, Action<object, int, StringBuilder> onrow) => ToSqlValuesOrSelectUnionAllExtension102(isValues, null, onrow);
|
||||
public string ToSqlValuesOrSelectUnionAllExtension102(bool isValues, Action<object, int, StringBuilder> onrowPre, Action<object, int, StringBuilder> onrow)
|
||||
public string ToSqlValuesOrSelectUnionAll(bool isValues = true) => ToSqlValuesOrSelectUnionAllExtension103(isValues, null, null, false);
|
||||
public string ToSqlValuesOrSelectUnionAllExtension101(bool isValues, Action<object, int, StringBuilder> onrow) => ToSqlValuesOrSelectUnionAllExtension103(isValues, null, onrow, false);
|
||||
public string ToSqlValuesOrSelectUnionAllExtension102(bool isValues, Action<object, int, StringBuilder> onrowPre, Action<object, int, StringBuilder> onrow) => ToSqlValuesOrSelectUnionAllExtension103(isValues, null, onrow, false);
|
||||
string ToSqlValuesOrSelectUnionAllExtension103(bool isValues, Action<object, int, StringBuilder> onrowPre, Action<object, int, StringBuilder> onrow, bool isAsTableSplited)
|
||||
{
|
||||
if (_source == null || _source.Any() == false) return null;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (_table.AsTableImpl != null && isAsTableSplited == false && _source == _sourceOld)
|
||||
{
|
||||
var atarr = _source.Select(a => new
|
||||
{
|
||||
item = a,
|
||||
splitKey = _table.AsTableImpl.GetTableNameByColumnValue(_table.AsTableColumn.GetValue(a), true)
|
||||
}).GroupBy(a => a.splitKey, a => a.item).ToArray();
|
||||
if (atarr.Length > 1)
|
||||
{
|
||||
var oldSource = _source;
|
||||
var arrret = new List<List<T1>>();
|
||||
foreach (var item in atarr)
|
||||
{
|
||||
_source = item.ToList();
|
||||
sb.Append(ToSqlValuesOrSelectUnionAllExtension103(isValues, onrowPre, onrow, true)).Append("\r\n\r\n;\r\n\r\n");
|
||||
}
|
||||
_source = oldSource;
|
||||
if (sb.Length > 0) sb.Remove(sb.Length - 9, 9);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append('(');
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values)
|
||||
|
@ -125,7 +125,9 @@ namespace FreeSql.Internal
|
||||
{
|
||||
if (!string.IsNullOrEmpty(trytb.Name)) attr.Name = trytb.Name;
|
||||
if (!string.IsNullOrEmpty(trytb.OldName)) attr.OldName = trytb.OldName;
|
||||
if (trytb._DisableSyncStructure != null) attr._DisableSyncStructure = trytb.DisableSyncStructure;
|
||||
if (trytb._DisableSyncStructure != null) attr._DisableSyncStructure = trytb.DisableSyncStructure;
|
||||
if (!string.IsNullOrEmpty(trytb.AsTable)) attr.AsTable = trytb.AsTable;
|
||||
|
||||
}
|
||||
var attrs = type.GetCustomAttributes(typeof(TableAttribute), false);
|
||||
foreach (var tryattrobj in attrs)
|
||||
@ -135,10 +137,12 @@ namespace FreeSql.Internal
|
||||
if (!string.IsNullOrEmpty(tryattr.Name)) attr.Name = tryattr.Name;
|
||||
if (!string.IsNullOrEmpty(tryattr.OldName)) attr.OldName = tryattr.OldName;
|
||||
if (tryattr._DisableSyncStructure != null) attr._DisableSyncStructure = tryattr.DisableSyncStructure;
|
||||
if (!string.IsNullOrEmpty(tryattr.AsTable)) attr.AsTable = tryattr.AsTable;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(attr.Name)) return attr;
|
||||
if (!string.IsNullOrEmpty(attr.OldName)) return attr;
|
||||
if (attr._DisableSyncStructure != null) return attr;
|
||||
if (!string.IsNullOrEmpty(attr.AsTable)) return attr;
|
||||
return null;
|
||||
}
|
||||
public ColumnAttribute GetEntityColumnAttribute(Type type, PropertyInfo proto)
|
||||
|
@ -27,6 +27,8 @@ namespace FreeSql.Internal.Model
|
||||
public bool IsRereadSql { get; internal set; }
|
||||
public bool IsDictionaryType { get; internal set; }
|
||||
|
||||
public IAsTable AsTableImpl { get; internal set; }
|
||||
public ColumnInfo AsTableColumn { get; internal set; }
|
||||
public ColumnInfo VersionColumn { get; set; }
|
||||
|
||||
ConcurrentDictionary<string, TableRef> _refs { get; } = new ConcurrentDictionary<string, TableRef>(StringComparer.CurrentCultureIgnoreCase);
|
||||
|
@ -393,6 +393,7 @@ namespace FreeSql.Internal
|
||||
if (trytb.VersionColumn.Attribute.MapType.IsNullableType() || trytb.VersionColumn.Attribute.MapType.IsNumberType() == false && trytb.VersionColumn.Attribute.MapType != typeof(byte[]))
|
||||
throw new Exception($"属性{trytb.VersionColumn.CsName} 被标注为行锁(乐观锁)(IsVersion),但其必须为数字类型 或者 byte[],并且不可为 Nullable");
|
||||
}
|
||||
tbattr?.ParseAsTable(trytb);
|
||||
|
||||
var indexesDict = new Dictionary<string, IndexInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||
//从数据库查找主键、自增、索引
|
||||
|
Reference in New Issue
Block a user