Hi Kavan -
[NEW "TABLE SPLITTING" ANSWER IN COMMENT BELOW
keeping this answer intact for continuity / posterity ]
Great question ... and one that troubles everyone who confronts a table with a blob in it ... whether you use DevForce, EF, ... another ORM ... raw ADO ... anything.
The best answer is always the same: get that big blog OUT of the table. Move it out to another table. Then build a related entity mapped to that blob table to which you can navigate.
Let's say you have an Employee and the Employee's Photo. Move the Photo out of the Employee table. If you're going to keep the photo in the database (not the only approach), put it in an EmployeePhoto table. Then you have an Employee entity that is trim and an EmployeePhoto entity which you fetch on demand (asynchronously one hopes).
Whenever I see this question, I give this advice. When I give this advice, people either take it ... or they tell me that they can't.
The only acceptable reason for taking my advice ... is if you have legacy code that depends upon the blob being there and you are truly stuck with that legacy code.
Now I would fight like a cornered rat to escape this bind. I'd try to fake out the legacy code if I code. Maybe define a view and have the legacy code point to the view. All the better if the legacy code uses stored procedures to update the Employee. Then you split the table behind the scenes and no one is the wiser.
If you are trapped, I will continue with some alternatives. But if there is any possible way of moving the blob out ... stop ... read no further ... please just do it.
----
Ok ... you're still reading ... which means that you're determined to keep the blob in the table.
This will cost you. It will cost you in complexity if nothing else. Here we go.
The Project + CUD Approach
You can separate the Query-for-Read code path from the Create/Update/Delete (CUD) code path.
When you want Employees for presentation purposes, you issue a "projection" query that returns only the properties of Employee that you want to retrieve in a list.
Anonymous Type Query
Here' how you'd write a query to project Employee into an anonymous type
var q1= EM.Employees
.Where(e => e.City == "Boston") // Example select
// Here comes the "projection"
var q2 = q1.Select(e => new {ID = e.ID, FirstName = e.FirstName, ...}) // Everything but the photo
// We'll use a synchronous queries for this example; you'd use async in the real world.
var emps = q2.ToList();
Unfortunately, "emps" is a list of some anonymous type. That's pretty hard to work with.
You want a client-side type that is public, that you can talk about, potentially bind to. The type will be strictly read only ... you won't use it to for editing. It's simply a Data Transfer Object (DTO).
Suppose we call it "EmployeeDto". We want to fill it on the Server-side and have DevForce move it over the wire for us. So we'll make it serializable. We'll write it as part of our Server project and link to it in our Silverlight project (I'm assuming Silverlight here):
[DataContract]
[ReadOnly(true)] // UI hint to make entire class ReadOnly
public partial class EmployeeDto: IKnownType {
[DataMember] public int ID { get; set; }
[DataMember] public string FirstName { get; set; }
// More core fields
}
We rewrite our query like so:
var q2 = q1.Select( e =>
new EmployeeDto {
ID = e.ID, FirstName = e.FirstName, ...} // Everything but the photo
)
Ok, now that you have EmployeeDtos, what do you do with them? You present them.
How do you perform CUD operations? Not on the EmployeeDtos! When it's time to make changes, you work with whole Employee entities.
Presumably, you'll do so one at a time and happily pay the price of bringing down the blob as needed. When the user selects an EmployeeDTO and "drills in to edit", you'll extract the Employee's ID and fetch the matching Employee from the database.
Now you have the full Employee ... with the photo. But you were going to get the photo anyway, right? At least you're only getting one photo, not every photo of every employee in the list.
Important note: EmployeeDto is NOT an entity. EmployeeDto is just a read-only bag of Employee data. The query result is not in cache. If you query aqain with the same criteria you'll get a conceptually duplicate set of EmployeeDtos.
You shouldn't edit one of these things - don't be fooled by the public setters. You've got no validation or other business logic. You can't save this data back to the database (as it is now ... we have tricks ... but that's a different post).
The DTO has no navigation properties to any other entities. You can enrich the DTO with such properties if you like; it's not hard but it's plumbing you'll have to write.
Oh ... don't forget to "update" your EmployeeDto after the user edits the corresponding Employee. Remember that the Employee and the EmployeeDto have no knowledge of each other.
This is not what you signed up for when you chose DevForce. You're going back to managing your data by hand. If you're doing a lot of this kind of thing, stop ... and reflect ... because you're not using DevForce as it was intended to be used. You are developing in a different paradigm. Not a bad paradigm, just a different one.
There is a way to get closer to the DevForce paradigm. It requires a little more setup. It's the View approach.
The View Approach
Question: is the blob field nullable. Please say "yes". Because, if it is nullable, you can define in your database an updatable view over the Employee Table ... a view that excludes the EmployeePhoto column. Then you can create another view consisting of just the EmployeeID and the EmployeePhoto. And then you create two entities AS IF there were two tables.
Entity Framework (and, therefore, DevForce) will permit you to define ReadOnly entities for these views. You can define Insert, Update, and Delete methods in EF for the Employee entity. For EmployeePhoto you should define Update and Delete ... never Insert; the act of creating a new Employee will result in an EmployeePhoto.
Consult Julie Lerman's book on Entity Framework for details on these aspects of Entity Framework. She'll tell you how to write the CUD methods that make view-backed entities modifiable.
I'm not going to go further into the details of this approach. To be honest, I haven't checked on our support for View CUD methods in DevForce 2010 RC and we may have postponed that support until a future release.
We will support it and, even if we don't have that support baked in right now, I have a workaround in my back pocket to tide you over. I'm sure you'll let me know if this is the way you want to go.
Edited by WardBell - 22-Apr-2010 at 3:59pm