LINQ to SQL tips and tricks #2
A few more useful and lesser-known tips for using LINQ to SQL.
Take full control of the TSQL
There are times when LINQ to SQL refuses to cook up the TSQL you wanted either because it doesn’t support the feature or because it has a different idea of what makes an optimal query.
In either case, the Translate method allows you to deliver your own TSQL to LINQ to SQL, to execute, with materialization and identity mapping still honored. For example:
var db = new PeopleContext();
if (db.Connection.State == System.Data.ConnectionState.Closed)
db.Connection.Open();
var cmd = db.GetCommand(db.Persons.Where(p => p.CountryID == 1));
cmd.CommandText = cmd.CommandText.Replace("[People] AS [t0]", "[People] AS [t0] WITH (NOLOCK)");
var results = db.Translate<Person>(cmd.ExecuteReader());
Complex stored procedures
When working with stored procedures, the LINQ to SQL designer and SQLMetal tools need to figure out what the return type is. To do this without actually running the stored procedure, they use the SET FMTONLY
command so that SQL Server parses the stored procedure but does not execute it.
Unfortunately, this parsing does not extend to dynamic SQL or temporary tables, so you must change the return type from the scalar integer to one of the known entity types by hand. You could use the following command at the start to let it run, regardless of the subsequent warning.
SET FMTONLY OFF
If your stored procedure can not safely handle calls at any time with null parameters, set the return type by hand instead.
Cloning an entity
There are many reasons you might want to clone an entity – you may want to create many similar ones, you could want to keep it around longer than the DataContext it came from – whatever your reason implementing a Clone method can be a pain but taking advantage of the DataContractSerializer can make light work of this providing your DBML is set to enable serialization.
If you use discriminator subclassing, you need to either ensure your type is cast to its concrete type or use my L2ST4 templates for now as .NET 3.5 SP1 doesn’t emit the necessary KnownType attributes to make this automatically happen (fixed in .NET 4.0). Add a simple method to serialize in-memory like this:
public static T Clone<T>(T source) {
var dcs = new System.Runtime.Serialization.DataContractSerializer(typeof(T));
using (var ms = new System.IO.MemoryStream()) {
dcs.WriteObject(ms, source);
ms.Seek(0, System.IO.SeekOrigin.Begin);
return (T)dcs.ReadObject(ms);
}
}
And then to clone:
var source = myQuery.First();
var cloned = Clone(source);
Be aware that this comes with a little overhead in the serialization and de-serialization process.
If this is a problem for you, why not grab the templates and make your entities implement ICloneable!
Check out part 3 of LINQ to SQL tips
[)amien
4 responses