/// <summary>
        ///
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="tableName"></param>
        /// <param name="mappings"></param>
        /// <param name="bulkCopyTimeout"></param>
        /// <param name="identityBehavior"></param>
        /// <param name="dbSetting"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private static async Task <NpgsqlBinaryImporter> GetNpgsqlBinaryImporterAsync(NpgsqlConnection connection,
                                                                                      string tableName,
                                                                                      IEnumerable <NpgsqlBulkInsertMapItem> mappings,
                                                                                      int?bulkCopyTimeout,
                                                                                      BulkImportIdentityBehavior identityBehavior,
                                                                                      IDbSetting dbSetting,
                                                                                      CancellationToken cancellationToken = default)
        {
            var copyCommand = GetBinaryImportCopyCommand(tableName,
                                                         mappings,
                                                         identityBehavior,
                                                         dbSetting);

#if NET5_0
            var importer = await connection.BeginBinaryImportAsync(copyCommand, cancellationToken);
#else
            var importer = await Task.FromResult(connection.BeginBinaryImport(copyCommand));
#endif

            // Timeout
            if (bulkCopyTimeout.HasValue)
            {
                importer.Timeout = TimeSpan.FromSeconds(bulkCopyTimeout.Value);
            }

            // Return
            return(importer);
        }
Esempio n. 2
0
        public async Task LoadAsync(Tenant tenant, ISerializer serializer, NpgsqlConnection conn, IEnumerable <T> documents,
                                    CancellationToken cancellation)
        {
            using var writer = await conn.BeginBinaryImportAsync(MainLoaderSql (), cancellation).ConfigureAwait(false);

            foreach (var document in documents)
            {
                _storage.AssignIdentity(document, tenant.TenantId, tenant.Database);
                await writer.StartRowAsync(cancellation).ConfigureAwait(false);
                await LoadRowAsync(writer, document, tenant, serializer, cancellation).ConfigureAwait(false);
            }

            await writer.CompleteAsync(cancellation).ConfigureAwait(false);
        }
        protected async Task InsertAsync <T>(DbContext context, Type type, IList <T> entities, TableInfo tableInfo, Action <decimal> progress, CancellationToken cancellationToken, bool isAsync)
        {
            NpgsqlConnection connection = tableInfo.NpgsqlConnection;
            bool             closeConnectionInternally = false;

            if (connection == null)
            {
                (connection, closeConnectionInternally) =
                    isAsync ? await OpenAndGetNpgsqlConnectionAsync(context, tableInfo.BulkConfig, cancellationToken).ConfigureAwait(false)
                            : OpenAndGetNpgsqlConnection(context, tableInfo.BulkConfig);
            }

            try
            {
                string sqlCopy = SqlQueryBuilderPostgreSql.InsertIntoTable(tableInfo, tableInfo.InsertToTempTable ? OperationType.InsertOrUpdate : OperationType.Insert);

                using var writer = isAsync ? await connection.BeginBinaryImportAsync(sqlCopy, cancellationToken).ConfigureAwait(false)
                                           : connection.BeginBinaryImport(sqlCopy);

                var uniqueColumnName = tableInfo.PrimaryKeysPropertyColumnNameDict.Values.ToList().FirstOrDefault();

                var doKeepIdentity       = tableInfo.BulkConfig.SqlBulkCopyOptions == SqlBulkCopyOptions.KeepIdentity;
                var propertiesColumnDict = ((tableInfo.InsertToTempTable || doKeepIdentity) && tableInfo.IdentityColumnName == uniqueColumnName)
                    ? tableInfo.PropertyColumnNamesDict
                    : tableInfo.PropertyColumnNamesDict.Where(a => a.Value != tableInfo.IdentityColumnName);

                var propertiesNames     = propertiesColumnDict.Select(a => a.Key).ToList();
                var entitiesCopiedCount = 0;
                foreach (var entity in entities)
                {
                    if (isAsync)
                    {
                        await writer.StartRowAsync(cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        writer.StartRow();
                    }

                    foreach (var propertyName in propertiesNames)
                    {
                        if (tableInfo.DefaultValueProperties.Contains(propertyName) && !tableInfo.PrimaryKeysPropertyColumnNameDict.ContainsKey(propertyName))
                        {
                            continue;
                        }

                        var propertyValue      = tableInfo.FastPropertyDict.ContainsKey(propertyName) ? tableInfo.FastPropertyDict[propertyName].Get(entity) : null;
                        var propertyColumnName = tableInfo.PropertyColumnNamesDict.ContainsKey(propertyName) ? tableInfo.PropertyColumnNamesDict[propertyName] : string.Empty;

                        var columnType = tableInfo.ColumnNamesTypesDict[propertyColumnName];

                        // string is 'text' which works fine
                        if (columnType.StartsWith("character")) // when MaxLength is defined: 'character(1)' or 'character varying'
                        {
                            columnType = "character";           // 'character' is like 'string'
                        }
                        else if (columnType.StartsWith("varchar"))
                        {
                            columnType = "varchar";
                        }
                        else if (columnType.StartsWith("numeric"))
                        {
                            columnType = "numeric";
                        }

                        var convertibleDict = tableInfo.ConvertibleColumnConverterDict;
                        if (convertibleDict.ContainsKey(propertyColumnName) && convertibleDict[propertyColumnName].ModelClrType.IsEnum)
                        {
                            if (propertyValue != null)
                            {
                                var clrType = tableInfo.ConvertibleColumnConverterDict[propertyColumnName].ProviderClrType;
                                if (clrType == typeof(byte)) // columnType == "smallint"
                                {
                                    propertyValue = (byte)propertyValue;
                                }
                                if (clrType == typeof(short))
                                {
                                    propertyValue = (short)propertyValue;
                                }
                                if (clrType == typeof(Int32))
                                {
                                    propertyValue = (int)propertyValue;
                                }
                                if (clrType == typeof(Int64))
                                {
                                    propertyValue = (long)propertyValue;
                                }
                                if (clrType == typeof(string))
                                {
                                    propertyValue = propertyValue.ToString();
                                }
                            }
                        }

                        if (isAsync)
                        {
                            await writer.WriteAsync(propertyValue, columnType, cancellationToken).ConfigureAwait(false);
                        }
                        else
                        {
                            writer.Write(propertyValue, columnType);
                        }
                    }
                    entitiesCopiedCount++;
                    if (progress != null && entitiesCopiedCount % tableInfo.BulkConfig.NotifyAfter == 0)
                    {
                        progress?.Invoke(ProgressHelper.GetProgress(entities.Count, entitiesCopiedCount));
                    }
                }
                if (isAsync)
                {
                    await writer.CompleteAsync(cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    writer.Complete();
                }
            }
            finally
            {
                if (closeConnectionInternally)
                {
                    //connection.Close();
                    if (isAsync)
                    {
                        await connection.CloseAsync();

                        //await context.Database.CloseConnectionAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        connection.Close();
                        //context.Database.CloseConnection();
                    }
                }
            }
        }