Showing posts with label LINQ to SQL. Show all posts
Showing posts with label LINQ to SQL. Show all posts

October 20, 2007

Software Development Essential Practices

I was in an interesting discussion last night: what software development practices do you consider essential? 

While opinions varied, I think there was some consensus on a few items.  In my list I also include some tools.  Some of these were mentioned by the group, but consider them my own additions.  Also, I am making this list specific to .NET, but the list applies to just about every language.

Universally agreed Practices

  • Source Control (1)
  • Local Development -- Every developer should have everything on their computer to run the system.  This includes all of the software and all of the source code.
  • Bug Tracking - nuf said.  There are to many tools available to list here.
  • TDD - Test Driven Development.  There was a little bit of back and forth, but the general consensus was that this should be done.
  • ORM - Object-Relational Mapping
    • NHibernate 
    • SubSonic - My person favorite
    • LINQ to SQL - not yet, but I feel this should be on the list.
    • LLBLGen ($) - Not free, but I've heard many good things about it.
    • More
  • Continuous Integration - Simple process that sits on a server and waits for things to get checked into your source control system.  When it sees something new, it gets all of the latest source code, compiles it, and runs all of the unit tests.  If there are any problems anywhere in that process it alerts the users (email, desktop icon, wave red flag, etc). (3)
  • One Step Build - it is unbelievably cool to be able to click one button and have your entire project compile, run all tests, and possibly create an install in one step.  Personally, I do like it, but with the current set of tools this is one of the hardest parts to setup.

Highly thought of but non-essential practices

I'm sure I have missed some tools in the list, but it is the practices that are more important anyway.  But if you put a comment about any tool that I missed I will add it to the list.

(1) Source Safe was notably not in the list.  While I don't like it either, it is better than nothing.  But if your team is greater than 5 people or you have multiple people working on the same project you really should look at one of the other products on the list.

(2) Not a unit testing library, but a Mock Object library.  Pick a unit testing libarary (NUnit, MBUnit, XUnit), then pick a mock object library (Rhino Mocks, TypeMock, NMock) to use with it.

(3) I really need to talk about continuous integration more.  But it is one of those things that leads you down a path.  First you add source control, then you start adhering to separation of concerns, then you start unit testing and mocking more, then you add continuous integration, and then one step builds are all part of the mix.  One best practice leads to another, but they don't make a bit of sense without some of the prior pieces.

(4) If you are a Code Rush person instead of a ReSharper person -- carry on, you are in good company.

($) The cost money - not just beer, but may have free version versions as well.

August 24, 2007

LINQ to SQL: Interfaces on your Domain objects

There has been some gowning about the lack of interfaces built into the domain objects produced by the Linq to SQL code generator.

Note: a domain object, as I am using the term here, is an object that maps column-to-property with a table. For example, if you have a Customer table with an ID and a Name field, you will have a Customer class with an ID and Name property.

I found that it is trivially easy to create. Every object in Linq to SQL is a partial class. So create a partial class that maps to the generated partial (there is no good way to say that, I swear). Then you can use the built in refactoring "Extract Interface" to create an interface that implements the fields in domain object.

The key point that I did not realize is this: you can assign an interface to class in any of the partial class declarations.

So, in Linq to SQL, keeping with our Customer table paradym, your generated partial class will look like this:

public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged

Now your other partial class (in an entirely different file) will look like this:

public partial class Customer : ICustomer

Both declarations define interfaces. I didn't know you could do that.

Now the cool part is that the interface can be defined anywhere. If you are trying to create a true separation between layers you will probably want to define it an an assembly other than the assembly that the domain classes are defined in.

Anyway, that is my discovery for today. Have a good weekend.

August 22, 2007

LINQ to SQL: Extension Methods

I've talked about Extension Methods (I probably called them partial methods) before. Now that I actually have Linq to SQL in my hands I thought I would take a look at what extension methods are created when you start with LINQ to SQL.

In my previous example, I showed a sample database that looked like this:


My designer is named "LinqTests.dbml", which is an xml file that is used to generate LinqTests.designer.cs. That is where we find all of the code.

First, we will look at the classes that map to the tables. We have a Customer, Product, and CustomerProduct tables. In each class there is a region named "Extensibility Method Definitions", that is where we are looking right now.

For the Customer class, this is what we see:


Basically, that accounts for two extension methods for every column in a table, plus three more: OnLoaded(), OnValidate(), and OnCreated().

If you can't tell from the name: OnCreated is called right as a new Customer object is created, the OnLoaded() is called after data is loaded into it by Linq to Sql, and OnValidate is called before the code is saved (I think -- since I can't find the code that actually calls it).

The others are for before and after a particular property is set.

Looking into the code further you can see how the code is being called. Here is the constructor:

public Customer()
{
    OnCreated();
    this._CustomerProducts = new EntitySet<CustomerProduct>(
new
Action<CustomerProduct>(this.attach_CustomerProducts),
new Action<CustomerProduct>(this.detach_CustomerProducts));
}

The line OnCreated(); calls the OnCreated method (duh!), but if you search the code you wont find anywhere that OnCreated does anything. That is for you to do in a partial class.

Now, to add some business logic to my Customer class for when the class is created or loaded, the code will look like this:



public partial class Customer
{
    partial void OnCreated()
    {
        this.Name = "Billy-Mac";
    }
    partial void OnLoaded()
    {
        if (string.Empty( this.Name ))
            this.Name = "Jim-Bob";
    }
}


Back to basics here. The generated DataContext class also has some Extension Methods



So now you have three extension methods for each table that the Data Context has to manage. One for Insert, Update, and Delete; plus one more for when the Data Context class is created.


Lets take a step back now. Does this really get us anywhere? Before, with generated domain objects (those are the objects that are created to hold data) you could still accomplish all of this using inheritance. The problem with using inheritance is that now you have to use the inherited class and shouldn't user the base class. Worse, there really isn't a good way to tell people not to use the base classes.

Now with extension methods you will have less need to inherit your base domain objects. Now you have the hooks you need to extend your domain objects to fit your business needs. Your developers (or just yourself) now have one set of objects to remember to use. Kind of like one stop shopping.

I've still heard a bit of moaning and groaning about extension methods on the web -- I don't agree with them. I think extension methods are a wonderful addition to C# that will really help fix a need. And what Linq for SQL has done has only helped to illustrate that need for everyone.

LINQ to SQL: Many-To-Many Tables and Joins

Still having fun with LINQ to SQL over here. One quick note, I've found that the best way to test LINQ queries is to have a unit test class ready to go. Makes things much easier.

So what I've been playing with lately is using LINQ to SQL for querying against Many-To-Many tables. For an illustration, I'll use a table structure like this: (click on it to see a bigger version)


Once imported into your Linq to Sql file type in visual studio, and viewed through a class diagram, you get this:



In my Customer table I have 5 customers, I also have 5 products (Product ID=1 is "Computer"). The CustomerProduct table has about 20 records.

Now we can start having fun with some queries. The question I wanted to answer was: "Which customers have a particular product?". Simple enough.

I found, as with many things, there are multiple ways of getting the same answer. My first query looked like this:


int Computer = 1;
LinqTestsDataContext cx = new LinqTestsDataContext();
var customersWithProduct = from c in cx.Customers
from cp in c.CustomerProducts
where cp.ProductID == Computer
select c;


OK, background note. This code is using the LinqTestsDataContext object to query the Customer table and the CustomerProduct table to find all of the customers with a Computer (product id = 1). What is returned is a IQueryiable object. If I want to parse through each Customer object indivitually, can call customersWithProduct.ToList() and get a List object returned.

This lovely piece of Linq generates the following SQL code:


{SELECT [t0].[ID], [t0].[Name]
FROM [dbo].[Customer] AS [t0], [dbo].[CustomerProduct] AS [t1]
WHERE ([t1].[ProductID] = @p0) AND ([t1].[CustomerID] = [t0].[ID])}


How do I know that is the SQL that is generated? After I run that line I can mouse over the variable (customersWithProduct) and the tooltip displays the generated SQL. I cant change it (that I know of), but at least I can look at it.

Anyway, that is not what I would call the best SQL I have ever seen -- and it is slow.

Next came attempt two at Linq to SQL. I wrote this:


int Computer = 1;
LinqTestsDataContext cx = new LinqTestsDataContext();
var customersWithProduct = from c in cx.Customers
join cp in cx.CustomerProducts on c.ID equals cp.CustomerID
where cp.ProductID == Computer
select c;


In the previous example, I used that Customer.CustomerProducts object to filter the products. This time I am explicitly joining the Customers and the CustomerProducts tables together in Linq. The only odd part of the query was the "equal" keyword that you have to use in the join.

The SQL generated was much better:


{SELECT [t0].[ID], [t0].[Name]
FROM [dbo].[Customer] AS [t0]
INNER JOIN [dbo].[CustomerProduct] AS [t1] ON [t0].[ID] = [t1].[CustomerID]
WHERE [t1].[ProductID] = @p0}


Look: an actual join. Trust me, this works much faster. The first query took 3.24 seconds, the second took 0.06 seconds. I call that significant. Especially considering the amount of data I am querying (not much). You add some real data (thousand and millions of records) and you could be talking about some significant downtime.

Lots more to discover here. All a matter of time.