Does SqlCommand.Clone()
create a deep copy or shallow copy? Also, is it safe to call Clone()
from multiple threads concurrently (create one command that multiple threads can copy, set parameter values, and execute)?

- 4,224
- 3
- 39
- 57
-
For more information about cloning, deep versus shallow copies, and examples, see the [Object.MemberwiseClone](http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx) method http://stackoverflow.com/questions/699210/why-should-i-implement-icloneable-in-c/4186747#4186747 – Sreekumar P Jul 26 '11 at 04:47
-
The reason for my question was if it is threadsafe to Clone() SqlCommand from multiple threads at the same time. From the discussion it seems that is true, so even though it isn't a deep clone, it does clone the parameter set. So at start-up you can prepare the SqlCommand once, then later clone it from many threads in parallel to save some work. – yzorg Sep 08 '11 at 19:02
2 Answers
It is not safe to call Clone
from multiple threads because the SqlCommand
class itself is not a thread safe class. you should lock
before cloning..
However you can look at the SqlCommand.Clone()
method using programs like Reflector
, here is the actual code:
public SqlCommand Clone()
{
SqlCommand command = new SqlCommand(this);
Bid.Trace("<sc.SqlCommand.Clone|API> %d#, clone=%d#\n", this.ObjectID, command.ObjectID);
return command;
}
internal static void Trace(string fmtPrintfW, int a1, int a2)
{
if (((modFlags & ApiGroup.Trace) != ApiGroup.Off) && (modID != NoData))
{
NativeMethods.Trace(modID, UIntPtr.Zero, UIntPtr.Zero, fmtPrintfW, a1, a2);
}
}
[DllImport("System.Data.dll", EntryPoint="DllBidTraceCW", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
internal static extern void Trace(IntPtr hID, UIntPtr src, UIntPtr info, string fmtPrintfW, int a1, int a2);
private SqlCommand(SqlCommand from) : this()
{
this.CommandText = from.CommandText;
this.CommandTimeout = from.CommandTimeout;
this.CommandType = from.CommandType;
this.Connection = from.Connection;
this.DesignTimeVisible = from.DesignTimeVisible;
this.Transaction = from.Transaction;
this.UpdatedRowSource = from.UpdatedRowSource;
SqlParameterCollection parameters = this.Parameters;
foreach (object obj2 in from.Parameters)
{
parameters.Add((obj2 is ICloneable) ? (obj2 as ICloneable).Clone() : obj2);
}
}
You can see that it create a new instance and add to it all properties of the old one, but it does not deep copy all properties "like Connection
for instance" and so it a shallow copy.

- 15,906
- 7
- 45
- 68
-
I don't expect it to clone critcal resources like SqlConnection. I would say because it clones all the parameters that are ICloneable that it is performing a 'best-attempt' at a deep copy. In the app I'm reviewing it never uses the 'original' SqlCommand, so the Connection and Transaction properties will always be null on the 'from' or 'original' instance. – yzorg Jul 26 '11 at 07:40
-
@yzorg: right, but because it doesn't clone all data deeply "like `SqlConnection`, `Parameters`.." it is then considered a shallow copy. It only considered a `deep copy` if it copies all data deeply, so if you change any property from the original or the copy, it will not effect the other one in anyway. – Jalal Said Jul 26 '11 at 07:47
The SqlCommand.Clone
method performs a shallow copy. Any properties that are a reference type will represent the same object in both SqlCommand instances. So, not thread safe.
AFAIK, all Clone() (MemberwiseClone) methods in the .NET framework are shallow copies.
You haven't posted your code, but I would suggest creating a new SqlCommand
rather than cloning.

- 295,962
- 43
- 465
- 541