LINQ to SQL, (LtS) is an “object relational mapping” (ORM) implementation from Microsoft shipping with the .NET Framework which allows developers to model a relational database using .NET classes. Once modeled, LtS exposes a rich expression language to query your database. LtS will saves time in designing a data layer because it uses code generation. You simply add a design diagram to your project and drag and drop database objects onto the diagram. Saving the diagram automatically generates your data classes.
While this is quick and easy to use, there’s one limitation: over the course of a development project, it’s inevitable that your database will change. Using LtS, you either need to manually update the entity through the designer or delete and add back the entity, losing your customizations. With today’s tight project schedules, doing the same work over and over again is something you want to avoid. Suddenly it dawns on you that the savings you are achieving through code-generation doesn’t make up for customization frustration.
Enter PLINQO (http://www.plinqo.com/), which stands for Professional LINQ to Objects. PLINQOÂ is a collection of CodeSmith (http://www.codesmithtools.com/)Â templates that are meant to replace and extend the LINQ to SQL designers that are included with Visual Studio 2008. PLINQO adds a slew of cool new features to your data layer while preserving all the things you like about LtS. Code generation, when implemented properly can be a huge productivity booster in your development efforts.
With PLINQO, you decide which tables you want to include in your data layer. PLINQO has a few templates: one for creating your dbml file, one for creating entities, and one for creating either a manager class or a query class. You can tweak template properties to fine tune the generated output. What’s really cool is that after creating your data layer with PLINQO you can even use the Visual Studio O/R diagram to perform further tweaking of the dbml file which will be preserved when regeneration takes place. That’s sweet.
PLINQO supports syncing the database with the dbml while preserving any manual dbml customizations you have made.It’s worth noting that there are other third party tools that address this like Hugati (http://www.huagati.com) which is a great product. However, PLINQO does much more than just keep the db in sync with your classes. Read on…
With PLINQO you have the option to generate a manager or query extension class for each entity. With Linq it is tempting to spread your data access code throughout your application. This may be ok for small prototype sites. However, it soon becomes cumbersome and difficult to manage for large scale projects. These special classes are wrappers around your entities which help you encapsulate your data access in one place.
One of the biggest complaints about Linq is its lack of support for detaching objects and passing them around, then reattach on the receiving side. I know many developers who passed on Linq because it lacked this feature. PLINQO supports entity detach so you can create an object in one context detach it and attach it to another context. I believe this feature will make a lot of people take a second look at LtS.
PLINQO takes advantage of the DataContractSerializer in WCF to provide a quality cloning solution for all entity objects. Each entity has a Clone method. Now you can load an object from the db, clone it, change one or more properties and save it as a new object.
Caching is one of the most effective strategies for boosting application performance. What’s nice about PLINQO is it extends the entities with a FromCache method. Under the hood, PLINQO uses the .Net built in cache object and the FromCache has numerous overloads. Hence you have all the flexibility of the .Net cache object available as an extension method. You just load your data as you usually do. Then if you want to cache it, just call one of the overloaded FromCache methods to automatically cache the data. The following code snippet illustrates how to load a Fruit object, and then cache it for 5 minutes on a sliding scale.
var fruit = context.Task.ByFruitId (FruitId) .FromCache(TimeSpan.FromMinutes(5));
PLINQO creates partial classes resulting in 2 files for each entity, manager and query extension. One file is the generated file and the other is for your custom code. Having all of this done for you is a huge productivity booster. Improved code organization makes complex sites easier to manage.
Below is a sample of a generated manager class for a single entity. Notice that it contains a private static class for compiled queries. Ignore this for now. We’ll revisit that later. When initially generated, this class is a stub. I added the GetBlock method. This method retrieves a block from the repository and returns a block object.
public partial class cbkManager
{
public Block GetBlock(string blockName)
{
return Entity.FirstOrDefault(p => p.BlockName == blockName);
}
#region Query
// A private class for lazy loading static compiled queries.
private static partial class Query
{
}
#endregion
}
Now anytime we need a block, we simply call up the manager like this:
DataContext db = new DataContext();
Block found = db.Manager.ContentBlock.GetBlock("blockName");
Now let’s assume at the time this function is written site traffic is light. However, as time passes and traffic grows, this function might need some optimization to help it handle the increased load. The LtS team’s solution to this is to give you the option to pre-compile your query. Pre-compiled queries run a lot faster as the entire expression tree doesn’t have to be built on each call. Suppose we sprinkled our data access code throughout the UI layer. We would have to find every place it’s called and replace that call with a compiled query. That’s tedious, time consuming and prone to errors. This illustrates the importance of good organized code design.
The better way is to change one function in a single place and the rest of the site uses the compiled query automatically. Below I illustrate how this is done using the PLINQO generated code.
public Block GetBlock(string blockName)
{
if (Context.LoadOptions == null)
return Query.GetBlock.Invoke(Context, blockName);
else
return Entity.FirstOrDefault(p => p.BlockName == blockName);
}
#region Query
// A private class for lazy loading static compiled queries.
private static partial class Query
{
// Add your compiled queries here.
internal static readonly Func<.Data.DataContext, string, Context.Data.Block> GetBlock =
System.Data.Linq.CompiledQuery.Compile(
(Context.Data.DataContext db, string BlockName) =>
db.ContentBlock.FirstOrDefault(c => c.BlockName == BlockName));
}
Now is a good time to revisit that partial static class I mentioned earlier. We simply added a compiled query to this class and then two lines of code to the GetBlock function to hook it up. I like having the internal static compiled query class right there where it should be. Intuitive and well organized code increases productivity, speeds up development and makes site maintenance easier and less prone to bugs.
Remember, we only have one manager and one manager class for this entity. The rest of the application gets a big boost from our small change. Since the calls come through the manager, this code which is sprinkled around the site on many pages is this:
DataContext db = new DataContext();
Block found = db.Manager.ContentBlock.GetBlock("blockName");
We don’t have to change that code. It calls the same GetBlock function. Except now that function will use the compiled query. This is one of the big advantages of a good design. LtS does make it tempting to sprinkle data access code throughout your site. I think this is poor design and will not scale well I like the idea of having the compiled query right there in the same file as the function. This nicely encapsulates all Block data access in one place. In five minutes, we were able to give the site a nice performance boost.
In conclusion, it’s worth noting that there are lots of conflicting rumors out there in the blogosphere about the future support for LtS coming out of Redmond. The messages are murky and it would be great to get some clarity on its future direction. It’s worth keeping this in mind when choosing your data layer. In view of this, it’s nice to see things like PLINQO which adds so much value to LtS.
I like LtS and have used it successfully on projects here at SolutionSet. PLINQO looks promising and introduces many more features beyond the scope of this blog post like meta attributes, a rule system for validating business rules, etc. If you like working with LtS, its worth taking a look at PLINQO to see if it fits your needs.
Happy Coding!
This entry was posted on Monday, August 31st, 2009 at 9:06 am and is filed under Technology. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.