using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace SqlSugar { public class InsertableProvider : IInsertable where T : class, new() { public SqlSugarClient Context { get; set; } public IAdo Ado { get { return Context.Ado; } } public ISqlBuilder SqlBuilder { get; set; } public InsertBuilder InsertBuilder { get; set; } public bool IsMappingTable { get { return this.Context.MappingTables != null && this.Context.MappingTables.Any(); } } public bool IsMappingColumns { get { return this.Context.MappingColumns != null && this.Context.MappingColumns.Any(); } } public bool IsSingle { get { return this.InsertObjs.Length == 1; } } public EntityInfo EntityInfo { get; set; } public List MappingColumnList { get; set; } private List IgnoreColumnNameList { get; set; } private bool IsOffIdentity { get; set; } public T[] InsertObjs { get; set; } public MappingTableList OldMappingTableList { get; set; } public bool IsAs { get; set; } public bool IsEnableDiffLogEvent { get; set; } public DiffLogModel diffModel { get; set; } private Action RemoveCacheFunc { get; set; } #region Core public virtual int ExecuteCommand() { if (InsertBuilder.DbColumnInfoList.HasValue()) { var pks = GetPrimaryKeys(); foreach (var item in InsertBuilder.DbColumnInfoList) { var isPk = pks.Any(y => y.Equals(item.DbColumnName, StringComparison.CurrentCultureIgnoreCase)) || item.IsPrimarykey; if (isPk && item.PropertyType == UtilConstants.GuidType && item.Value.ObjToString() == Guid.Empty.ToString()) { item.Value = Guid.NewGuid(); if (InsertObjs.First().GetType().GetProperties().Any(it => it.Name == item.PropertyName)) InsertObjs.First().GetType().GetProperties().First(it => it.Name == item.PropertyName).SetValue(InsertObjs.First(), item.Value, null); } } } InsertBuilder.IsReturnIdentity = false; PreToSql(); AutoRemoveDataCache(); string sql = InsertBuilder.ToSqlString(); RestoreMapping(); Before(sql); var result = Ado.ExecuteCommand(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()); After(sql, null); return result; } public virtual KeyValuePair> ToSql() { InsertBuilder.IsReturnIdentity = true; PreToSql(); AutoRemoveDataCache(); string sql = InsertBuilder.ToSqlString(); RestoreMapping(); return new KeyValuePair>(sql, InsertBuilder.Parameters); } public virtual int ExecuteReturnIdentity() { InsertBuilder.IsReturnIdentity = true; PreToSql(); AutoRemoveDataCache(); string sql = InsertBuilder.ToSqlString(); RestoreMapping(); Before(sql); var result = Ado.GetInt(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()); After(sql, result); return result; } public virtual long ExecuteReturnBigIdentity() { InsertBuilder.IsReturnIdentity = true; PreToSql(); AutoRemoveDataCache(); string sql = InsertBuilder.ToSqlString(); RestoreMapping(); Before(sql); var result = Convert.ToInt64(Ado.GetScalar(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray())); After(sql, result); return result; } public virtual T ExecuteReturnEntity() { ExecuteCommandIdentityIntoEntity(); return InsertObjs.First(); } public virtual bool ExecuteCommandIdentityIntoEntity() { var result = InsertObjs.First(); var identityKeys = GetIdentityKeys(); if (identityKeys.Count == 0) { return this.ExecuteCommand() > 0; } var idValue = ExecuteReturnBigIdentity(); Check.Exception(identityKeys.Count > 1, "ExecuteCommandIdentityIntoEntity does not support multiple identity keys"); var identityKey = identityKeys.First(); object setValue = 0; if (idValue > int.MaxValue) setValue = idValue; else setValue = Convert.ToInt32(idValue); this.Context.EntityMaintenance.GetProperty(identityKey).SetValue(result, setValue, null); return idValue > 0; } public Task ExecuteCommandAsync() { Task result = new Task(() => { IInsertable asyncInsertable = CopyInsertable(); return asyncInsertable.ExecuteCommand(); }); TaskStart(result); return result; } public Task ExecuteReturnIdentityAsync() { Task result = new Task(() => { IInsertable asyncInsertable = CopyInsertable(); return asyncInsertable.ExecuteReturnIdentity(); }); TaskStart(result); return result; } public Task ExecuteReturnEntityAsync() { Task result = new Task(() => { IInsertable asyncInsertable = CopyInsertable(); return asyncInsertable.ExecuteReturnEntity(); }); TaskStart(result); return result; } public Task ExecuteCommandIdentityIntoEntityAsync() { Task result = new Task(() => { IInsertable asyncInsertable = CopyInsertable(); return asyncInsertable.ExecuteCommandIdentityIntoEntity(); }); TaskStart(result); return result; } public Task ExecuteReturnBigIdentityAsync() { Task result = new Task(() => { IInsertable asyncInsertable = CopyInsertable(); return asyncInsertable.ExecuteReturnBigIdentity(); }); TaskStart(result); return result; } #endregion #region Setting public IInsertable AS(string tableName) { var entityName = typeof(T).Name; IsAs = true; OldMappingTableList = this.Context.MappingTables; this.Context.MappingTables = this.Context.Utilities.TranslateCopy(this.Context.MappingTables); if (this.Context.MappingTables.Any(it => it.EntityName == entityName)) { this.Context.MappingTables.Add(this.Context.MappingTables.First(it => it.EntityName == entityName).DbTableName, tableName); } this.Context.MappingTables.Add(entityName, tableName); return this; ; } public IInsertable IgnoreColumns(Expression> columns) { var ignoreColumns = InsertBuilder.GetExpressionValue(columns, ResolveExpressType.ArraySingle).GetResultArray().Select(it => this.SqlBuilder.GetNoTranslationColumnName(it)).ToList(); this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => !ignoreColumns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList(); return this; } public IInsertable IgnoreColumns(Func ignoreColumMethod) { this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => !ignoreColumMethod(it.PropertyName)).ToList(); return this; } public IInsertable InsertColumns(Expression> columns) { var ignoreColumns = InsertBuilder.GetExpressionValue(columns, ResolveExpressType.ArraySingle).GetResultArray().Select(it => this.SqlBuilder.GetNoTranslationColumnName(it)).ToList(); this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => ignoreColumns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList(); return this; } public IInsertable InsertColumns(string[] columns) { this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => columns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList(); return this; } public IInsertable InsertColumns(Func insertColumMethod) { this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => insertColumMethod(it.PropertyName)).ToList(); return this; } public IInsertable With(string lockString) { if (this.Context.CurrentConnectionConfig.DbType == DbType.SqlServer) this.InsertBuilder.TableWithString = lockString; return this; } public IInsertable Where(bool isNoInsertNull, bool isOffIdentity = false) { this.IsOffIdentity = isOffIdentity; if (this.InsertBuilder.LambdaExpressions == null) this.InsertBuilder.LambdaExpressions = InstanceFactory.GetLambdaExpressions(this.Context.CurrentConnectionConfig); this.InsertBuilder.IsNoInsertNull = isNoInsertNull; return this; } public IInsertable RemoveDataCache() { this.RemoveCacheFunc = () => { var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService; CacheSchemeMain.RemoveCache(cacheService, this.Context.EntityMaintenance.GetTableName()); }; return this; } public IInsertable EnableDiffLogEvent(object businessData = null) { Check.Exception(this.InsertObjs.HasValue() && this.InsertObjs.Count() > 1, "DiffLog does not support batch operations"); diffModel = new DiffLogModel(); this.IsEnableDiffLogEvent = true; diffModel.BusinessData = businessData; diffModel.DiffType = DiffType.insert; return this; } #endregion #region Protected Methods private void AutoRemoveDataCache() { var moreSetts = this.Context.CurrentConnectionConfig.MoreSettings; var extService = this.Context.CurrentConnectionConfig.ConfigureExternalServices; if (moreSetts != null && moreSetts.IsAutoRemoveDataCache && extService != null && extService.DataInfoCacheService != null) { this.RemoveDataCache(); } } protected virtual void PreToSql() { #region Identities if (!IsOffIdentity) { List identities = GetIdentityKeys(); if (identities != null && identities.Any()) { this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => { return !identities.Any(i => it.DbColumnName.Equals(i, StringComparison.CurrentCultureIgnoreCase)); }).ToList(); } } #endregion #region IgnoreColumns if (this.Context.IgnoreColumns != null && this.Context.IgnoreColumns.Any()) { var currentIgnoreColumns = this.Context.IgnoreColumns.Where(it => it.EntityName == this.EntityInfo.EntityName).ToList(); this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => { return !currentIgnoreColumns.Any(i => it.PropertyName.Equals(i.PropertyName, StringComparison.CurrentCulture)); }).ToList(); } if (this.Context.IgnoreInsertColumns != null && this.Context.IgnoreInsertColumns.Any()) { var currentIgnoreColumns = this.Context.IgnoreInsertColumns.Where(it => it.EntityName == this.EntityInfo.EntityName).ToList(); this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => { return !currentIgnoreColumns.Any(i => it.PropertyName.Equals(i.PropertyName, StringComparison.CurrentCulture)); }).ToList(); } #endregion if (this.IsSingle) { foreach (var item in this.InsertBuilder.DbColumnInfoList) { if (this.InsertBuilder.Parameters == null) this.InsertBuilder.Parameters = new List(); var paramters = new SugarParameter(this.SqlBuilder.SqlParameterKeyWord + item.DbColumnName, item.Value, item.PropertyType); if (InsertBuilder.IsNoInsertNull && paramters.Value == null) { continue; } this.InsertBuilder.Parameters.Add(paramters); } } } internal void Init() { InsertBuilder.EntityInfo = this.EntityInfo; Check.Exception(InsertObjs == null || InsertObjs.Count() == 0, "InsertObjs is null"); int i = 0; foreach (var item in InsertObjs) { List insertItem = new List(); if (item is Dictionary) { SetInsertItemByDic(i, item, insertItem); } else { SetInsertItemByEntity(i, item, insertItem); } this.InsertBuilder.DbColumnInfoList.AddRange(insertItem); ++i; } } private void SetInsertItemByDic(int i, T item, List insertItem) { foreach (var column in item as Dictionary) { var columnInfo = new DbColumnInfo() { Value = column.Value, DbColumnName = column.Key, PropertyName = column.Key, PropertyType = column.Value == null ? DBNull.Value.GetType() : UtilMethods.GetUnderType(column.Value.GetType()), TableId = i }; if (columnInfo.PropertyType.IsEnum()) { columnInfo.Value = Convert.ToInt64(columnInfo.Value); } insertItem.Add(columnInfo); } } private void SetInsertItemByEntity(int i, T item, List insertItem) { foreach (var column in EntityInfo.Columns) { if (column.IsIgnore || column.IsOnlyIgnoreInsert) continue; var columnInfo = new DbColumnInfo() { Value = column.PropertyInfo.GetValue(item, null), DbColumnName = GetDbColumnName(column.PropertyName), PropertyName = column.PropertyName, PropertyType = UtilMethods.GetUnderType(column.PropertyInfo), TableId = i }; if (columnInfo.PropertyType.IsEnum()) { columnInfo.Value = Convert.ToInt64(columnInfo.Value); } insertItem.Add(columnInfo); } } private string GetDbColumnName(string propertyName) { if (!IsMappingColumns) { return propertyName; } if (this.Context.MappingColumns.Any(it => it.EntityName.Equals(EntityInfo.EntityName, StringComparison.CurrentCultureIgnoreCase))) { this.MappingColumnList = this.Context.MappingColumns.Where(it => it.EntityName.Equals(EntityInfo.EntityName, StringComparison.CurrentCultureIgnoreCase)).ToList(); } if (MappingColumnList == null || !MappingColumnList.Any()) { return propertyName; } else { var mappInfo = this.MappingColumnList.FirstOrDefault(it => it.PropertyName.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase)); return mappInfo == null ? propertyName : mappInfo.DbColumnName; } } protected virtual List GetPrimaryKeys() { if (this.Context.IsSystemTablesConfig) { return this.Context.DbMaintenance.GetPrimaries(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName)); } else { return this.EntityInfo.Columns.Where(it => it.IsPrimarykey).Select(it => it.DbColumnName).ToList(); } } protected virtual List GetIdentityKeys() { if (this.Context.IsSystemTablesConfig) { return this.Context.DbMaintenance.GetIsIdentities(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName)); } else { return this.EntityInfo.Columns.Where(it => it.IsIdentity).Select(it => it.DbColumnName).ToList(); } } private void TaskStart(Task result) { if (this.Context.CurrentConnectionConfig.IsShardSameThread) { Check.Exception(true, "IsShardSameThread=true can't be used async method"); } result.Start(); } protected void RestoreMapping() { if (IsAs) { this.Context.MappingTables = OldMappingTableList; } } protected IInsertable CopyInsertable() { var asyncContext = this.Context.Utilities.CopyContext(true); asyncContext.CurrentConnectionConfig.IsAutoCloseConnection = true; asyncContext.IsAsyncMethod = true; var asyncInsertable = asyncContext.Insertable(this.InsertObjs); var asyncInsertableBuilder = asyncInsertable.InsertBuilder; asyncInsertableBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList; asyncInsertableBuilder.EntityInfo = this.InsertBuilder.EntityInfo; asyncInsertableBuilder.Parameters = this.InsertBuilder.Parameters; asyncInsertableBuilder.sql = this.InsertBuilder.sql; asyncInsertableBuilder.IsNoInsertNull = this.InsertBuilder.IsNoInsertNull; asyncInsertableBuilder.IsReturnIdentity = this.InsertBuilder.IsReturnIdentity; asyncInsertableBuilder.EntityInfo = this.InsertBuilder.EntityInfo; asyncInsertableBuilder.TableWithString = this.InsertBuilder.TableWithString; if (this.RemoveCacheFunc != null) { asyncInsertable.RemoveDataCache(); } return asyncInsertable; } private void After(string sql, long? result) { if (this.IsEnableDiffLogEvent) { var parameters = InsertBuilder.Parameters; if (parameters == null) parameters = new List(); diffModel.AfterData = GetDiffTable(sql, result); diffModel.Time = this.Context.Ado.SqlExecutionTime; if (this.Context.Ado.DiffLogEvent != null) this.Context.Ado.DiffLogEvent(diffModel); } if (this.RemoveCacheFunc != null) { this.RemoveCacheFunc(); } } private void Before(string sql) { if (this.IsEnableDiffLogEvent) { var parameters = InsertBuilder.Parameters; if (parameters == null) parameters = new List(); diffModel.BeforeData = null; diffModel.Sql = sql; diffModel.Parameters = parameters.ToArray(); } } private List GetDiffTable(string sql, long? identity) { List parameters = new List(); List result = new List(); var whereSql = string.Empty; List cons = new List(); if (identity != null && identity > 0 && GetIdentityKeys().HasValue()) { var fieldName = GetIdentityKeys().Last(); cons.Add(new ConditionalModel() { ConditionalType = ConditionalType.Equal, FieldName = fieldName, FieldValue = identity.ToString() }); } else { foreach (var item in this.EntityInfo.Columns.Where(it => it.IsIgnore == false && GetPrimaryKeys().Any(pk => pk.Equals(it.DbColumnName, StringComparison.CurrentCultureIgnoreCase)))) { var fielddName = item.DbColumnName; var fieldValue = this.EntityInfo.Columns.FirstOrDefault(it => it.PropertyName == item.PropertyName).PropertyInfo.GetValue(this.InsertObjs.Last(), null).ObjToString(); cons.Add(new ConditionalModel() { ConditionalType = ConditionalType.Equal, FieldName = fielddName, FieldValue = fieldValue }); } } Check.Exception(cons.IsNullOrEmpty(), "Insertable.EnableDiffLogEvent need primary key"); var sqlable = this.Context.Utilities.ConditionalModelToSql(cons); whereSql = sqlable.Key; parameters.AddRange(sqlable.Value); var dt = this.Context.Queryable().Where(whereSql).AddParameters(parameters).ToDataTable(); if (dt.Rows != null && dt.Rows.Count > 0) { foreach (DataRow row in dt.Rows) { DiffLogTableInfo item = new DiffLogTableInfo(); item.TableDescription = this.EntityInfo.TableDescription; item.TableName = this.EntityInfo.DbTableName; item.Columns = new List(); foreach (DataColumn col in dt.Columns) { DiffLogColumnInfo addItem = new DiffLogColumnInfo(); addItem.Value = row[col.ColumnName]; addItem.ColumnName = col.ColumnName; addItem.ColumnDescription = this.EntityInfo.Columns.First(it => it.DbColumnName.Equals(col.ColumnName, StringComparison.CurrentCultureIgnoreCase)).ColumnDescription; item.Columns.Add(addItem); } result.Add(item); } return result; } else { DiffLogTableInfo diffTable = new DiffLogTableInfo(); diffTable.TableName = this.EntityInfo.DbTableName; diffTable.TableDescription = this.EntityInfo.TableDescription; diffTable.Columns = this.EntityInfo.Columns.Where(it => it.IsIgnore == false).Select(it => new DiffLogColumnInfo() { ColumnDescription = it.ColumnDescription, ColumnName = it.DbColumnName, Value = it.PropertyInfo.GetValue(this.InsertObjs.Last(), null) }).ToList(); return new List() { diffTable }; } } #endregion } }