升级到 .net 6 时,WriteToServerAsync 无法按预期工作

问题描述 投票:0回答:2

我当前的项目是.net 5,我已经升级到.net 6版本。 早些时候,代码工作正常,但升级后,此代码似乎无法工作。

        public async Task AddBulkAsync(List<T> entityList)
        {
            try
            {
                if (entityList.Count > 0)
                {
                    using (var sqlBulkCopy = GetSqlBulkCopy(this._dbContext, this._dbContext.Database.CurrentTransaction))
                    {
                        sqlBulkCopy.BatchSize = 10000;
                        sqlBulkCopy.BulkCopyTimeout = 1800;
                        var dataTable = GetDataTable(entityList, sqlBulkCopy);
                        await sqlBulkCopy.WriteToServerAsync(dataTable);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        internal DataTable GetDataTable<T>(IList<T> entities, SqlBulkCopy sqlBulkCopy)
        {
            var dataTable = new DataTable();
            var columnsDict = new Dictionary<string, object>();
            var ownedEntitiesMappedProperties = new HashSet<string>();

            var type = entities[0].GetType();
            var entityType = this._dbContext.Model.FindEntityType(type);
            //var entityPropertiesDict = entityType.GetProperties().Where(a => tableInfo.PropertyColumnNamesDict.ContainsKey(a.Name)).ToDictionary(a => a.Name, a => a);
            var entityPropertiesDict = entityType.GetProperties().ToDictionary(a => a.Name, a => a);
            var entityNavigationOwnedDict = entityType.GetNavigations().Where(a => a.GetTargetType().IsOwned()).ToDictionary(a => a.Name, a => a);
            var properties = type.GetProperties();
            // var discriminatorColumn = tableInfo.ShadowProperties.Count == 0 ? null : tableInfo.ShadowProperties.ElementAt(0);

            foreach (var property in properties)
            {
                if (entityPropertiesDict.ContainsKey(property.Name))
                {
                    var propertyEntityType = entityPropertiesDict[property.Name];
                    string columnName = propertyEntityType.GetColumnName();

                    // var isConvertible = tableInfo.ConvertibleProperties.ContainsKey(columnName);
                    var propertyType = property.PropertyType;

                    var underlyingType = Nullable.GetUnderlyingType(propertyType);
                    if (underlyingType != null)
                    {
                        propertyType = underlyingType;
                    }

                    dataTable.Columns.Add(columnName, propertyType);
                    columnsDict.Add(property.Name, null);
                }
            }


            foreach (var entity in entities)
            {
                foreach (var property in properties)
                {
                    if (entityPropertiesDict.ContainsKey(property.Name))
                    {
                        var propertyValue = property.GetValue(entity, null);
                        if (property.PropertyType == typeof(Guid) && (Guid)propertyValue == default(Guid))
                        {
                            propertyValue = Guid.NewGuid();
                        }

                        columnsDict[property.Name] = propertyValue;
                    }
                }
                var record = columnsDict.Values.ToArray();
                dataTable.Rows.Add(record);
            }

            foreach (DataColumn item in dataTable.Columns)  //Add mapping
            {
                sqlBulkCopy.ColumnMappings.Add(item.ColumnName, item.ColumnName);
            }
            string schema = entityType.GetSchema() != null ? entityType.GetSchema() : "dbo";
            dataTable.TableName = schema + "." + entityType.GetTableName();
            sqlBulkCopy.DestinationTableName = dataTable.TableName;
            return dataTable;
        }

        private SqlBulkCopy GetSqlBulkCopy(DbContext dbContext, IDbContextTransaction transaction)
        {
            var sqlConnection = dbContext.Database.GetDbConnection().ConnectionString;
            if (transaction == null)
            {
                //return new SqlBulkCopy(sqlConnection, sqlBulkCopyOptions, null);
                return new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.CheckConstraints);
            }
            else
            {
                var sqlTransaction = (SqlTransaction)transaction.GetDbTransaction();
                //return new SqlBulkCopy(sqlConnection, sqlBulkCopyOptions, sqlTransaction);
                return new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.CheckConstraints);
            }
        }

这似乎没有按预期工作

await sqlBulkCopy.WriteToServerAsync(dataTable);
我尝试用非异步方法实现
sqlBulkCopy.WriteToServer(dataTable);
但仍然出现同样的问题 它返回一个错误

发生一个或多个错误。(用户“Devadmin”登录失败。)” 我已经尝试过 Task.Run 方法,它不会返回任何错误,但数据不会插入到表中。

 Task.Run(async () => await sqlBulkCopy.WriteToServerAsync(dataTable));

请有人帮助我解决这个问题。

c# .net .net-6.0 sqlbulkcopy sqlclient
2个回答
0
投票

问题是

DbConnection
已经打开了。因此,当您尝试检索连接字符串时,密码已被擦除。

您可以将

persist security info=true
添加到字符串中,但我建议不要这样做。

相反,重写您的

GetSqlBulkCopy
函数,该函数处理事务的方式从根本上被破坏了,因此它现在重用它接收到的连接对象,而不仅仅是连接字符串。

private SqlBulkCopy GetSqlBulkCopy(SqlConnection connection, DbContext dbContext)
{
    var sqlTransaction = _dbContext.Database.CurrentTransaction.GetDbTransaction() as SqlTransaction;
    return new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.CheckConstraints, sqltransaction);
}

然后

var sqlConnection = (SqlConnection)dbContext.Database.GetDbConnection();
var wasOpen = sqlConnection.ConnectionState == ConnectionState.Open
try
{
    using (var sqlBulkCopy = GetSqlBulkCopy(sqlConnection, this._dbContext))
    {
        //etc
        if (!wasOpen)
            await sqlConnection.OpenAsync();
        // etc
    }
}
finally
{
    if (!wasOpen)
        sqlConnection.Close();
}

0
投票

而不是在字符串中添加

persist security info=true
。我们可以使用以下代码。

                var sqlConnectionString = SqlConnectionToConnectionString((SqlConnection)this._dbContext.Database.GetDbConnection());
                var sqlConnection = new SqlConnection(sqlConnectionString);
                var wasOpen = sqlConnection.State == ConnectionState.Open;
                try
                {
                    using (var sqlBulkCopy = new SqlBulkCopy(sqlConnectionString, SqlBulkCopyOptions.CheckConstraints))
                    {
                        if (!wasOpen)
                            await sqlConnection.OpenAsync();
                        
                        sqlBulkCopy.BatchSize = 10000;
                        sqlBulkCopy.BulkCopyTimeout = 1800;
                        var dataTable = GetDataTable(entityList, sqlBulkCopy);
                        await sqlBulkCopy.WriteToServerAsync(dataTable);
                    }
                }
                finally
                {
                    if (!wasOpen)
                        sqlConnection.Close();
                }
© www.soinside.com 2019 - 2024. All rights reserved.