Reputation: 34325
I have the following inline SQL:
internal void UpdateWorkflowProcessingByNullToken(Guid processingToken, int numberToProcess)
{
string sql = string.Format(CultureInfo.InvariantCulture,
"UPDATE TOP ({0}) Master.WorkflowEventProcessing " +
"SET ProcessingToken = '{1}' " +
"WHERE ProcessingToken IS NULL",
numberToProcess, processingToken);
this.Database.ExecuteCommand(sql);
}
Inline SQL was used for performance. It was my understanding that L2S would create a SQL statement for every row that I needed to update. And that was taking too long. Note, this was a couple of years ago.
Now I have a DBA telling me this:
As developers, we've been reluctant to use stored procedures. We like having all of our data code in our C# data layer. Am I stuck here? Do I need to use a stored procedure? Or is there a way to do a mass update with L2S?
I remember reading about compiling an L2S query. I could look into that as well...
Upvotes: 1
Views: 740
Reputation: 4950
You can use parameterized SQL commands to execute. This will generate a reusable query execution plan that will be as efficient as a stored procedure after it is initially created and cached. Each execution you simply supply new parameters.
More Details
Given the following code that updates a demo database and a table named "Foo"
///////////////////////////////////////////////////////////
// just setup for the context for demo purposes, you would
// reference this.Database in place of creating context.
SqlConnection connection = new SqlConnection("Data Source = .; Initial Catalog = MyDb; Integrated Security = SSPI;");
var dataContext = new System.Data.Linq.DataContext(connection);
///////////////////////////////////////////////////////////
string updateQuery = "UPDATE TOP (@p1) dbo.Foo " +
"SET Data = @p2 " +
"WHERE Data IS NULL";
dataContext.Connection.Open();
var command = dataContext.Connection.CreateCommand();
command.CommandText = updateQuery;
command.CommandType = System.Data.CommandType.Text;
var param1 = new SqlParameter("@p1", System.Data.SqlDbType.Int);
param1.Value = 3;
command.Parameters.Add(param1);
var param2 = new SqlParameter("@p2", System.Data.SqlDbType.Int);
param2.Value = 1;
command.Parameters.Add(param2);
command.Prepare();
command.ExecuteNonQuery();
param2.Value = 5;
command.ExecuteNonQuery();
From the profiler output you can see it calls sp_prepexec
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@p1 int,@p2 int',N'UPDATE TOP (@p1) dbo.Foo SET Data = @p2 WHERE Data IS NULL',@p1=3,@p2=1
select @p1
and executes the statement passing the parameters 3 and 1 then when param2.Value is set to 5 and the command executed again the profiler shows it reusing the prepared command (thus no recompiling or new execution plan generated)
exec sp_execute 1,@p1=3,@p2=5
This is what the profiler output looks like, FYI...
Upvotes: 3