I’ve blogged before about Flex & LINQ, but I’m always learning new things, and I wanted to share some of my most recent findings.
Note: this article focuses on Flex & LINQ, but it could as easily be applied to Silverlight & LINQ as well. Silverlight 3 is set to merge client & server with .NET 4.0, but I believe the issue of how much and when to send data between client & server will continue to be relevant.
First off, why LINQ?
- With LINQ on your server layer, you can avoid having to write your server value objects – LINQ to SQL will do that for you from your DB schema – allows you to quickly updates these objects if your schema ever changes (and let’s face it, it will). NOTE: unfortunately, there is no free & easy way to sync your LINQ to SQL context to your schema in VS2008).
- You can put all your SQL as strongly-typed code in your DAL rather than having to call the DB to do it via stored procs, which decouples your DB from your application, allowing you to switch databases if you ever wanted to, and keeps all your server code in one place.
- Cleaner and shorter code – easier for you, easier for other developers to understand (as long as they understand LINQ 🙂 )
So, if you’ve decided to take the LINQ option and your a Flex or AIR developer, then there is good news.
Products such as WebORB.NET and FluorineFx both support .NET 3.5 and will allow your Flex application to send Remote Objects back and forth between the two. Yes you could use Web Services to do communicate with the server, but I’m assuming you’ve read up on the performance benefits of remoting and AMF vs Web Services, and you’re opting for speed.
The question is however, how do you do it?
The LINQ to SQL tool (I’m not going to mention the ADO.NET Entities tool, which is more feature rich, but a touch more complicated) creates you a data context as you know. This remembers the actions you perform on your objects and will propagate the changes back to the DB when you “SubmitChanges()”. However, when you’re working on the Flex/.NET model, you’re now using LINQ on an middle-tier (or even an n-tier) application, and that changes things.
What changes is that the “context” will be a new instance between each request (unless you use session access to the RemoteObjects, which I won’t get into here). LINQ won’t know that you changed something outside this context, and so to Update an object in the database you will need to “Attach()” it back to the current context to save it, along with it’s original but from a new context. (See examples below).
Now, there are plenty of articles out there on LINQ in the middle tier and LINQ with n-tier, so I won’t reinvent the wheel. What I will do is talk about strategies on how to leverage LINQ in your Flex app, and how to synchronise data.
Let’s take a think about possible methodologies for sending/receiving related object data from server to client:
- Safety method: take a little save a little
- Hungry method: take a little save lots
- Greedy method: take everything save lots
- Thrifty method: take everything save a little
I’ll use the following example to illustrate the different methods:
The safety method is a simple-to-follow, clear 1:1 system – load an object when you need it, and load the associated objects as you need them. When you save data back, call the server with either one or a collection of single unrelated objects. You rely on your foreign keys to do all the loading.
All associations within the LINQ to SQL designer (DBML) need to have INTERNAL access, to prevent them being sent to the client, and so that you can still use them within the server code.
For example: Your client wants the list of projects? It loads them simply via LINQ. Client wants the project’s list of Companies? Load them via the ProjectID. Need to save a Company, send the server the Company object with an associated ProjectID.
The hungry method involves retrieving just the data objects you require at the time and building up the object model on the client side, eventually sending back an object with related objects. This means you don’t have an excessive number of save calls back to the server, and you don’t rely on the foreign key, you rely on the attached object.
For example: You may want to load all Projects within the system via LINQ, but don’t want the associated Companies, Employees or Suburbs. You then want to create a new Project and create Companies, Employees. You then call one Save() method to save the new Project, and let LINQ create the entire collection of Company and Employee records.
Now, by default, LINQ will try to send you all the related Companies, Employees and related Suburbs when you ask for the list of Projects. You have two main options to avoid this:
- Change the ACCESS of the association(s) between parent and child within the DBML (LINQ to SQL) editor to INTERNAL. This means only inside the DLL could you access this property.
- In your server DLL, NULL any related properties before returning the data to the client. (Literally: project.Companies = null).
Do you see the problem? Option 1 is the obvious choice but then it means you couldn’t actually send the data back to .NET because if you tried to send a Project back with Companies attached, .NET would say that Project doesn’t have the Companies property as the association as it is internal (and the exception happens during unmarshalling on the server, handled by either the WebORB or FluorineFx DLL).
The Hungry method starts to become a real issue with visibility, and unfortunately, the easiest is to follow option 2 above, which is not a good solution in my opinion.
NOTE: When saving back to the server, do NOT send back both an associated object and an associated foreign key. This will cause .NET to except. EG: If you were to save a Company with an attached Project, you couldn’t also send back Company’s ProjectID (the FK), .NET wouldn’t know which association to use.
So, in your client code, either remove the Foreign Keys completely from the value object, or use a property getter only to get the foreign key from the association object.
The greedy method is expensive. You are always sending and receiving all (or a lot) of the data in a single call. The advantage is, less trips between the client and server, and minimal client & server code (one Save method to do everything!).
As you can imagine, debugging the Save method can be a headache – as debugging LINQ usually is 🙂
Now, to Update an object under the greedy method is tricky yet fun. You need to Attach() this new object to the context, along with it’s original from yet another context.
For example: You want to load all Employees and their Suburb plus their Company and it’s Project. If you wanted to save it back, you’d need to attach it back in.
Employee SaveEmployee(Employee e)
DataClassesDataContext context = new DataClassesDataContext();
//if is Update
if (e.EmployeeID > 0)
//need to attach Employee with a NEW INSTANCE of the DataContext
Employee oldEmployee = new DataClassesDataContext().Employees.Single( p => p.EmployeeID == e.EmployeeID);
//now attach it
This can get even tricker when you’re attaching objects with children which already exist. It can require going through the children and testing their Primary Keys using the method above.
The thrifty method involves receiving all the required data, and just sending back the minimal amount of objects back to the server for a successful save.
To prevent data being sent back to the server once it is already in the Flex client, requires the use of the Flex metatag: [Transient]. To use Thrifty, we need to rely on Foreign Key associations as LINQ will use the FK on the insert (just like saving in the Safety method). The advantage is that you have complete control over anything being saved into your database, which can be a real advantage in a intricate & lengthy project.
Generally using this method, you would need to recall all of your data again, as some associations have been modified. You can try an sychronise these on the client, but it can get VERY tricky. At the very least, you’ll need to return your saved object to get it’s ID if it was just inserted.
For example: You want to load all Projects from the system, but when you save a Project, you don’t t send back it’s Companies, this property is Transient on the client and doesn’t get send back to the server. If you wanted to save a Company, you’d send back a Company object without the associated Project object, but WITH the ProjectID Foreign Key.
I personally use a combination of the Thrifty and the Greedy method, deciding when I want to send all the data back, and when I just want to send back an individual object. It still means however, that I need to reload ALL of my data again after a successful save of some object.
The most important things to remember is attaching to a new context, and not sending both a foreign key and a related foreign object back to the server simultaneously – this upsets LINQ.
More examples and further investigation to come…