为每一行调用存储过程不起作用
Calling stored procedure for each row doesn't work
我在 foreach 循环中执行存储过程时遇到问题,这是我的代码:
var members = await _context.Members
.Where(x => !x.Deleted)
.ToListAsync(cancellationToken);
using (SqlConnection con = new SqlConnection("server=localhost;database=ProductsDb;User=user;Password=password"))
{
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
SqlDataReader reader = cmd.ExecuteReader(); // ON SECOND ITERATION OF FOREACH CODE BREAKS HERE
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
cmd.Parameters.Clear();
}
await _context.SaveChangesAsync(cancellationToken);
}
}
这是我的例外情况:
System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first.
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
如何在不引入数据表的情况下使用此代码solve/fix?
你必须调用 cmd.Parameters.Clear();每次执行命令后
.....
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
// What do you need this for ????
// cmd.ExecuteNonQuery();
using (var reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
_context.Entry(member).State = EntityState.Modified;
}
reader.Close();
}
cmd.Parameters.Clear()
}
另一种方法是重用参数而不是调用 clear();
.....
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value =Guid.Empty;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
foreach (var member in members)
{
cmd.Parameters["@memberId"].Value = member.Id;
.....
}
顺便问一下,你需要什么 cmd.ExecuteNonQuery();为了?
如果我的思路是正确的,你需要改变一件事。目前您在 foreach 循环之前声明 cmd,因此对于每个成员,您正在更改现有命令。
我认为你应该从这里开始:
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
// IN SECOND ITERATION CODE BREAKS HERE
cmd.ExecuteNonQuery();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
}
await _context.SaveChangesAsync(cancellationToken);
}
为此:
foreach (var member in members)
{
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
cmd.ExecuteNonQuery();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
await _context.SaveChangesAsync(cancellationToken);
}
}
在性能方面有更好的解决方案,这是肯定的,但它会完成它的工作。
你需要用 using
块来处理你的 reader。 不要试图用 .Close()
自己做,不值得:
using(SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
}
我在 foreach 循环中执行存储过程时遇到问题,这是我的代码:
var members = await _context.Members
.Where(x => !x.Deleted)
.ToListAsync(cancellationToken);
using (SqlConnection con = new SqlConnection("server=localhost;database=ProductsDb;User=user;Password=password"))
{
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
SqlDataReader reader = cmd.ExecuteReader(); // ON SECOND ITERATION OF FOREACH CODE BREAKS HERE
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
cmd.Parameters.Clear();
}
await _context.SaveChangesAsync(cancellationToken);
}
}
这是我的例外情况:
System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first.
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
如何在不引入数据表的情况下使用此代码solve/fix?
你必须调用 cmd.Parameters.Clear();每次执行命令后
.....
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
// What do you need this for ????
// cmd.ExecuteNonQuery();
using (var reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
_context.Entry(member).State = EntityState.Modified;
}
reader.Close();
}
cmd.Parameters.Clear()
}
另一种方法是重用参数而不是调用 clear();
.....
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value =Guid.Empty;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
foreach (var member in members)
{
cmd.Parameters["@memberId"].Value = member.Id;
.....
}
顺便问一下,你需要什么 cmd.ExecuteNonQuery();为了?
如果我的思路是正确的,你需要改变一件事。目前您在 foreach 循环之前声明 cmd,因此对于每个成员,您正在更改现有命令。 我认为你应该从这里开始:
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
foreach (var member in members)
{
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
// IN SECOND ITERATION CODE BREAKS HERE
cmd.ExecuteNonQuery();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
}
await _context.SaveChangesAsync(cancellationToken);
}
为此:
foreach (var member in members)
{
using (SqlCommand cmd = new SqlCommand("CalculateRolesForEachMember", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// open connection ProductsDb database
con.Open();
cmd.Parameters.Add("@memberId", SqlDbType.UniqueIdentifier).Value = member.Id;
cmd.Parameters.Add("@month", SqlDbType.Int).Value = (int)month;
cmd.Parameters.Add("@year", SqlDbType.Int).Value = (int)year;
cmd.ExecuteNonQuery();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
await _context.SaveChangesAsync(cancellationToken);
}
}
在性能方面有更好的解决方案,这是肯定的,但它会完成它的工作。
你需要用 using
块来处理你的 reader。 不要试图用 .Close()
自己做,不值得:
using(SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
member.MemberType = memberTypes.FirstOrDefault(x => x.Acronym == reader["Role"].ToString());
member.ModifiedDate = DateTime.Now;
}
}