SqlBulkCopy 登录失败。

5

当使用SQL Server身份验证时,我在使用SqlBulkCopy命令时遇到了问题。但是,在使用Windows身份验证时没有此问题。

SqlBulkCopy sbc = new SqlBulkCopy(sqConn.ConnectionString, SqlBulkCopyOptions.KeepIdentity);

这会抛出一个错误:

用户 'xx' 的登录失败

代码:

SqlBulkCopy sbc = new SqlBulkCopy(sqConn);

这个方法可以正常运行,但是无法保留标识列的原始值。


谢谢大家的编辑。下次我会记得把代码放入块中。 - davehay
4个回答

9
连接字符串中需要包含"persist security info=true"。否则,如果连接已经打开,则密码将从sqlConn.ConnectionString中删除。

谢谢。我花了两天时间弄清楚为什么外部应用程序可以进行身份验证,但SQLBulkCopy不能。将Persist Security Info=True设置解决了这个问题。 - William Smith

3

解决方案非常简单,但我仍然很想知道为什么SQL Server身份验证应该与Windows身份验证不同。

   using (SqlTransaction transaction =
                sqConn.BeginTransaction())
            {

                SqlBulkCopy sbc = new SqlBulkCopy(sqConn,SqlBulkCopyOptions.KeepIdentity,transaction);
                sbc.DestinationTableName = file;
                sbc.BatchSize = 1000;
                sbc.NotifyAfter = 1000;
                sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
                sbc.WriteToServer(SourceTable);
                transaction.Commit();
            }

那么解决方案是什么?据我所知,您没有更改身份验证。 - martennis
1
解决方法是使用事务,这样可以与 SQL Server 身份验证一起使用。我需要这个来批量复制到 Azure SQL 表中,因为 Azure AD 身份验证不可行。 - davehay
new SqlBulkCopy() has 4 overloads: SqlConnection only, SqlConnection/SqlBulkCopyOptions/SqlTransaction, string only, and string/SqlBulkCopyOptions. If you want to supply the copy option KeepIdentity, then you will have to supply something for the SqlTransaction, otherwise the compiler will try to match on the string/SqlBulkCopyOptions overload. As far as I know, there's nothing stopping you from just passing a null object for the SqlTransaction: new SqlBulkCopy(sqConn, SqlBulkCopyOptions.KeepIdentity, null) - Thorin
我还应该说一声,我不知道为什么,但是 SqlBulkCopy 类在使用 SQL Server 验证(用户名和密码在连接字符串中)的连接字符串时就是无法工作,因此当你的连接字符串包含 SQL Server 验证时,你必须将现有的 SqlConnection 对象传递给 SqlBulkCopy 对象。虽然这很奇怪,但事实就是如此。 - Thorin
请注意,使用 Windows 身份验证的原因是连接字符串中不包含密码。当连接被使用过一次之后,密码就会被删除。所以,在 SQL Server 身份验证中,你将不再拥有一个有效的连接字符串。我想 OP 在进行批量复制之前可能会对 'sqlConn' 进行另一个调用,并且默认情况下这会导致密码被删除。参见 https://dev59.com/AWcs5IYBdhLWcg3w8oXK - d219

0

试试这个,对我有用

private static void BulkInsert(DataTable dtExcel, SqlConnection con)
        {
            try
            {
                {
                    if (con.State == ConnectionState.Closed)
                        con.Open();
                    var sqlTransactionScope = con.BeginTransaction();

                    //Open bulkcopy connection.
                    using (SqlBulkCopy bulkcopy = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, sqlTransactionScope))
                    {
                        //Set destination table name
                        bulkcopy.BulkCopyTimeout = 0;
                        bulkcopy.BatchSize = 1000;
                        bulkcopy.DestinationTableName = "[dbo].[cc_alertowner]";

                        try
                        {

                            foreach (DataColumn col in dtExcel.Columns)
                            {
                                bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(col.ColumnName, col.ColumnName));
                            }
                            // bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("", ""));
                            // bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("DateCreated", "DateCreated"));

                            if (con.State == ConnectionState.Closed)
                                con.Open();

                            bulkcopy.WriteToServer(dtExcel);
                            sqlTransactionScope.Commit();
                        }
                        catch (Exception ex)
                        {
                            sqlTransactionScope.Rollback();
                            throw;
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

以上内容的解释将非常有帮助。 - d219
看起来这是我在原问题中描述的解决方案的一个实现,即在事务中包装复制。正如原回答中所解释的那样,这与将密码作为连接字符串的一部分进行传递有关。在第一次使用连接字符串之后,密码会从字符串中剥离,并导致失败。Windows身份验证没有涉及任何密码。另一种解决方案是在连接字符串中使用 persist security info = true,其具有相同的效果。 - davehay
有趣的是,这只发生在身份被保留的地方。 - davehay

-1

看起来你的 SQL Server 混合模式身份验证已关闭。

右键单击数据库实例并选择属性。 点击安全性,在服务器身份验证中选择第二个单选按钮 SQL Server 和 Windows 身份验证模式。

完成后,请从 services.msc 中重新启动 SQL 服务。


如果是这种情况,SQLBulkCopy的第二种格式也不会起作用。 - davehay
@davehay:您能否在配置文件中展示您正在使用的连接字符串? - Programming Geek
检查您的连接字符串中是否有“集成安全性”部分。如果是这样,请尝试从您的数据库连接字符串中删除“集成安全性”部分,然后再次尝试。这将设置您的连接使用Windows身份验证而不是SQL身份验证。 - Programming Geek
1
我很不情愿地给你点了个踩,因为你没有注意到问题或我的评论。 - davehay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接