Example #1
0
        /// <summary>批量插入</summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="list">实体列表</param>
        /// <param name="columns">要插入的字段,默认所有字段</param>
        /// <param name="session">指定会话,分表分库时必用</param>
        /// <returns>
        /// Oracle:当批量插入操作中有一条记录无法正常写入,则本次写入的所有数据都不会被写入(可以理解为自带事物)
        /// MySQL:当批量插入操作中有一条记录无法正常写入,则本次写入的所有数据都不会被写入(可以理解为自带事物)
        /// </returns>
        public static Int32 BatchInsert <T>(this IEnumerable <T> list, IDataColumn[] columns = null, IEntitySession session = null) where T : IEntity
        {
            if (list == null || !list.Any())
            {
                return(0);
            }

            var entity = list.First();
            var fact   = entity.GetType().AsFactory();

            if (columns == null)
            {
                columns = fact.Fields.Select(e => e.Field).ToArray();

                // 第一列数据包含非零自增,表示要插入自增值
                var id = columns.FirstOrDefault(e => e.Identity);
                if (id != null)
                {
                    if (entity[id.Name].ToLong() == 0)
                    {
                        columns = columns.Where(e => !e.Identity).ToArray();
                    }
                }

                // 每个列要么有脏数据,要么允许空。不允许空又没有脏数据的字段插入没有意义
                //var dirtys = GetDirtyColumns(fact, list.Cast<IEntity>());
                //if (fact.FullInsert)
                //    columns = columns.Where(e => e.Nullable || dirtys.Contains(e.Name)).ToArray();
                //else
                //    columns = columns.Where(e => dirtys.Contains(e.Name)).ToArray();
                if (!fact.FullInsert)
                {
                    var dirtys = GetDirtyColumns(fact, list.Cast <IEntity>());
                    columns = columns.Where(e => dirtys.Contains(e.Name)).ToArray();
                }
            }

            session ??= fact.Session;
            session.InitData();

            var dal = session.Dal;

            dal.CheckDatabase();
            //var tableName = dal.Db.FormatTableName(session.TableName);

            var tracer = dal.Tracer ?? DAL.GlobalTracer;

            using var span = tracer?.NewSpan($"db:{dal.ConnName}:BatchInsert:{session.TableName}");
            try
            {
                return(dal.Session.Insert(session.Table, columns, list.Cast <IExtend>()));
            }
            catch (Exception ex)
            {
                span?.SetError(ex, list);
                throw;
            }
        }
Example #2
0
        /// <summary>批量更新</summary>
        /// <remarks>
        /// 注意类似:XCode.Exceptions.XSqlException: ORA-00933: SQL 命令未正确结束
        /// [SQL:Update tablen_Name Set FieldName=:FieldName W [:FieldName=System.Int32[]]][DB:AAA/Oracle]
        /// 建议是优先检查表是否存在主键,如果由于没有主键导致,即使通过try...cache 依旧无法正常保存。
        /// </remarks>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="list">实体列表</param>
        /// <param name="columns">要更新的字段,默认所有字段</param>
        /// <param name="updateColumns">要更新的字段,默认脏数据</param>
        /// <param name="addColumns">要累加更新的字段,默认累加</param>
        /// <param name="session">指定会话,分表分库时必用</param>
        /// <returns></returns>
        public static Int32 BatchUpdate <T>(this IEnumerable <T> list, IDataColumn[] columns = null, ICollection <String> updateColumns = null, ICollection <String> addColumns = null, IEntitySession session = null) where T : IEntity
        {
            if (list == null || !list.Any())
            {
                return(0);
            }

            var entity = list.First();
            var fact   = entity.GetType().AsFactory();

            if (columns == null)
            {
                columns = fact.Fields.Select(e => e.Field).Where(e => !e.Identity).ToArray();
            }
            //if (updateColumns == null) updateColumns = entity.Dirtys.Keys;
            if (updateColumns == null)
            {
                // 所有实体对象的脏字段作为更新字段
                var dirtys = GetDirtyColumns(fact, list.Cast <IEntity>());
                // 创建时间等字段不参与Update
                dirtys = dirtys.Where(e => !e.StartsWithIgnoreCase("Create")).ToArray();

                if (dirtys.Length > 0)
                {
                    updateColumns = dirtys;
                }
            }
            if (addColumns == null)
            {
                addColumns = fact.AdditionalFields;
            }

            if ((updateColumns == null || updateColumns.Count < 1) && (addColumns == null || addColumns.Count < 1))
            {
                return(0);
            }

            session ??= fact.Session;
            session.InitData();

            var dal = session.Dal;

            dal.CheckDatabase();
            //var tableName = dal.Db.FormatTableName(session.TableName);

            var tracer = dal.Tracer ?? DAL.GlobalTracer;

            using var span = tracer?.NewSpan($"db:{dal.ConnName}:BatchUpdate:{session.TableName}");
            try
            {
                return(dal.Session.Update(session.Table, columns, updateColumns, addColumns, list.Cast <IExtend>()));
            }
            catch (Exception ex)
            {
                span?.SetError(ex, list);
                throw;
            }
        }
Example #3
0
        /// <summary>批量插入或更新</summary>
        /// <param name="entity">实体对象</param>
        /// <param name="columns">要插入的字段,默认所有字段</param>
        /// <param name="updateColumns">主键已存在时,要更新的字段</param>
        /// <param name="addColumns">主键已存在时,要累加更新的字段</param>
        /// <param name="session">指定会话,分表分库时必用</param>
        /// <returns>
        /// MySQL返回值:返回值相当于流程执行次数,及时insert失败也会累计一次执行(所以不建议通过该返回值确定操作记录数)
        /// do insert success = 1次;
        /// do update success =2次(insert 1次+update 1次),
        /// 简单来说:如果Insert 成功则返回1,如果需要执行的是update 则返回2,
        /// </returns>
        public static Int32 Upsert(this IEntity entity, IDataColumn[] columns = null, ICollection <String> updateColumns = null, ICollection <String> addColumns = null, IEntitySession session = null)
        {
            var fact = entity.GetType().AsFactory();

            if (columns == null)
            {
                columns = fact.Fields.Select(e => e.Field).Where(e => !e.Identity).ToArray();

                // 每个列要么有脏数据,要么允许空。不允许空又没有脏数据的字段插入没有意义
                //var dirtys = GetDirtyColumns(fact, new[] { entity });
                //if (fact.FullInsert)
                //    columns = columns.Where(e => e.Nullable || dirtys.Contains(e.Name)).ToArray();
                //else
                //    columns = columns.Where(e => dirtys.Contains(e.Name)).ToArray();
                if (!fact.FullInsert)
                {
                    var dirtys = GetDirtyColumns(fact, new[] { entity });
                    columns = columns.Where(e => e.PrimaryKey || dirtys.Contains(e.Name)).ToArray();
                }
            }
            if (updateColumns == null)
            {
                updateColumns = entity.Dirtys.Where(e => !e.StartsWithIgnoreCase("Create")).Distinct().ToArray();
            }
            if (addColumns == null)
            {
                addColumns = fact.AdditionalFields;
            }

            session ??= fact.Session;
            session.InitData();

            var dal = session.Dal;

            dal.CheckDatabase();
            //var tableName = dal.Db.FormatTableName(session.TableName);

            var tracer = dal.Tracer ?? DAL.GlobalTracer;

            using var span = tracer?.NewSpan($"db:{dal.ConnName}:Upsert:{session.TableName}");
            try
            {
                return(dal.Session.Upsert(session.Table, columns, updateColumns, addColumns, new[] { entity as IExtend }));
            }
            catch (Exception ex)
            {
                span?.SetError(ex, entity);
                throw;
            }
        }
Example #4
0
        /// <summary>批量插入或更新</summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="list">实体列表</param>
        /// <param name="columns">要插入的字段,默认所有字段</param>
        /// <param name="updateColumns">要更新的字段,默认脏数据</param>
        /// <param name="addColumns">要累加更新的字段,默认累加</param>
        /// <param name="session">指定会话,分表分库时必用</param>
        /// <returns>
        /// MySQL返回值:返回值相当于流程执行次数,及时insert失败也会累计一次执行(所以不建议通过该返回值确定操作记录数)
        /// do insert success = 1次;
        /// do update success =2次(insert 1次+update 1次),
        /// 简单来说:对于一行记录,如果Insert 成功则返回1,如果需要执行的是update 则返回2
        /// Oracle返回值:无论是插入还是更新返回的都始终为-1
        /// </returns>
        public static Int32 Upsert <T>(this IEnumerable <T> list, IDataColumn[] columns = null, ICollection <String> updateColumns = null, ICollection <String> addColumns = null, IEntitySession session = null) where T : IEntity
        {
            if (list == null || !list.Any())
            {
                return(0);
            }

            var entity = list.First();
            var fact   = entity.GetType().AsFactory();

            session ??= fact.Session;

            // SqlServer的批量Upsert需要主键参与,哪怕是自增,构建update的where时用到主键
            if (columns == null)
            {
                var dbt = session.Dal.DbType;
                if (dbt == DatabaseType.SqlServer || dbt == DatabaseType.Oracle)
                {
                    columns = fact.Fields.Select(e => e.Field).Where(e => !e.Identity || e.PrimaryKey).ToArray();
                }
                else if (dbt == DatabaseType.MySql)
                {
                    columns = fact.Fields.Select(e => e.Field).ToArray(); //只有标识键的情况下会导致重复执行insert方法 目前只测试了Mysql库
                }
                else
                {
                    columns = fact.Fields.Select(e => e.Field).Where(e => !e.Identity).ToArray();
                }

                // 每个列要么有脏数据,要么允许空。不允许空又没有脏数据的字段插入没有意义
                //var dirtys = GetDirtyColumns(fact, list.Cast<IEntity>());
                //if (fact.FullInsert)
                //    columns = columns.Where(e => e.Nullable || dirtys.Contains(e.Name)).ToArray();
                //else
                //    columns = columns.Where(e => dirtys.Contains(e.Name)).ToArray();
                if (!fact.FullInsert)
                {
                    var dirtys = GetDirtyColumns(fact, list.Cast <IEntity>());
                    columns = columns.Where(e => e.PrimaryKey || dirtys.Contains(e.Name)).ToArray();
                }
            }
            //if (updateColumns == null) updateColumns = entity.Dirtys.Keys;
            if (updateColumns == null)
            {
                // 所有实体对象的脏字段作为更新字段
                var dirtys = GetDirtyColumns(fact, list.Cast <IEntity>());
                // 创建时间等字段不参与Update
                dirtys = dirtys.Where(e => !e.StartsWithIgnoreCase("Create")).ToArray();

                if (dirtys.Length > 0)
                {
                    updateColumns = dirtys;
                }
            }
            if (addColumns == null)
            {
                addColumns = fact.AdditionalFields;
            }
            // 没有任何数据变更则直接返回0
            if ((updateColumns == null || updateColumns.Count <= 0) && (addColumns == null || addColumns.Count <= 0))
            {
                return(0);
            }

            session.InitData();

            var dal = session.Dal;

            dal.CheckDatabase();
            //var tableName = dal.Db.FormatTableName(session.TableName);

            var tracer = dal.Tracer ?? DAL.GlobalTracer;

            using var span = tracer?.NewSpan($"db:{dal.ConnName}:BatchUpsert:{session.TableName}");
            try
            {
                return(dal.Session.Upsert(session.Table, columns, updateColumns, addColumns, list.Cast <IExtend>()));
            }
            catch (Exception ex)
            {
                span?.SetError(ex, list);
                throw;
            }
        }
Example #5
0
        /// <summary>批量替换</summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="list">实体列表</param>
        /// <param name="columns">要插入的字段,默认所有字段</param>
        /// <param name="session">指定会话,分表分库时必用</param>
        /// <returns>
        /// Oracle:当批量插入操作中有一条记录无法正常写入,则本次写入的所有数据都不会被写入(可以理解为自带事物)
        /// MySQL:当批量插入操作中有一条记录无法正常写入,则本次写入的所有数据都不会被写入(可以理解为自带事物)
        /// </returns>
        public static Int32 BatchReplace <T>(this IEnumerable <T> list, IDataColumn[] columns = null, IEntitySession session = null) where T : IEntity
        {
            if (list == null || !list.Any())
            {
                return(0);
            }

            var entity = list.First();
            var fact   = entity.GetType().AsFactory();

            if (columns == null)
            {
                columns = fact.Fields.Select(e => e.Field).ToArray();

                // 第一列数据包含非零自增,表示要插入自增值
                var id = columns.FirstOrDefault(e => e.Identity);
                if (id != null)
                {
                    if (entity[id.Name].ToLong() == 0)
                    {
                        columns = columns.Where(e => !e.Identity).ToArray();
                    }
                }

                // 每个列要么有脏数据,要么允许空。不允许空又没有脏数据的字段插入没有意义
                if (!fact.FullInsert)
                {
                    var dirtys = GetInsertColumns(fact, list.Cast <IEntity>());
                    columns = columns.Where(e => dirtys.Contains(e.Name)).ToArray();
                }
            }

            session ??= fact.Session;
            session.InitData();

            var dal = session.Dal;
            //dal.CheckDatabase();

            var tracer = dal.Tracer ?? DAL.GlobalTracer;

            using var span = tracer?.NewSpan($"db:{dal.ConnName}:BatchReplace:{session.TableName}");
            try
            {
                if (span != null && list is ICollection collection)
                {
                    span.Tag = collection.Count + "";
                }

                var rs = dal.Session.Replace(session.Table, columns, list.Cast <IExtend>());

                // 清除脏数据,避免重复提交保存
                foreach (var item in list)
                {
                    item.Dirtys.Clear();
                }

                return(rs);
            }
            catch (Exception ex)
            {
                span?.SetError(ex, list);
                throw;
            }
        }