- 增加 [Table(AsTable = xx)] 分表特性,完成分表插入/删除;

This commit is contained in:
2881099
2022-04-08 21:19:51 +08:00
parent 8c022b3e0a
commit f73c02d8d1
28 changed files with 1413 additions and 744 deletions

View File

@ -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);

View File

@ -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
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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);
//从数据库查找主键、自增、索引