public static int BulkInsertTable <T>(IEnumerable <T> entities, SqlBulkCopyOptions copyOptions = SafeDefaults, bool preSaving = true, bool validateFirst = true, bool disableIdentity = false, int?timeout = null, string?message = null) where T : Entity { using (HeavyProfiler.Log(nameof(BulkInsertTable), () => typeof(T).TypeName())) { if (message != null) { return(SafeConsole.WaitRows(message == "auto" ? $"BulkInsering {entities.Count()} {typeof(T).TypeName()}" : message, () => BulkInsertTable(entities, copyOptions, preSaving, validateFirst, disableIdentity, timeout, message: null))); } if (disableIdentity) { copyOptions |= SqlBulkCopyOptions.KeepIdentity; } if (copyOptions.HasFlag(SqlBulkCopyOptions.UseInternalTransaction)) { throw new InvalidOperationException("BulkInsertDisableIdentity not compatible with UseInternalTransaction"); } var list = entities.ToList(); if (preSaving) { Saver.PreSaving(() => GraphExplorer.FromRoots(list)); } if (validateFirst) { Validate <T>(list); } var t = Schema.Current.Table <T>(); bool disableIdentityBehaviour = copyOptions.HasFlag(SqlBulkCopyOptions.KeepIdentity); DataTable dt = new DataTable(); var columns = t.Columns.Values.Where(c => !(c is SystemVersionedInfo.SqlServerPeriodColumn) && (disableIdentityBehaviour || !c.IdentityBehaviour)).ToList(); foreach (var c in columns) { dt.Columns.Add(new DataColumn(c.Name, ConvertType(c.Type))); } using (disableIdentityBehaviour ? Administrator.DisableIdentity(t, behaviourOnly: true) : null) { foreach (var e in list) { if (!e.IsNew) { throw new InvalidOperationException("Entites should be new"); } t.SetToStrField(e); dt.Rows.Add(t.BulkInsertDataRow(e)); } } using (var tr = new Transaction()) { Schema.Current.OnPreBulkInsert(typeof(T), inMListTable: false); Executor.BulkCopy(dt, columns, t.Name, copyOptions, timeout); foreach (var item in list) { item.SetNotModified(); } return(tr.Commit(list.Count)); } } }