I've been using Linq to SQL for a new implementation that I've been working on. I have about 5000 lines of code and am a little ways from a solid demo. I've been pretty satisfied with Linq to SQL so far -- the tools are excellent and pretty painless and it allows you to get a DAL up and running quickly.
That said, there are some major draw backs that I just keep hitting over and over again. Namely how to handle separation of concerns between my DAL and my business layer and juggling that with different data contexts.
Here is the architecture I've been using: My repositories do all my data access and they return Linq to SQL objects. Each of my Linq to SQL objects implements an IDetachable interface. A typical implementation looks like this:
partial class PaymentDetail : IDetachable
{
#region IDetachable Members
public bool IsAttached
{
get { return PropertyChanging != null; }
}
public void Detach()
{
if (IsAttached)
{
PropertyChanged = null;
PropertyChanging = null;
Transaction.Detach();
}
}
#endregion
}
Every time I do a DAL operation in my repository I "detach" when I'm done with the object (and it should theoretically detach from any child objects) to remove the DataContext's context.
Like I said, this works pretty well, but there are some edge cases that seem to be a big pain in the ass. For instance, my Transaction object has many PaymentDetails. Even when there are no PaymentDetails in that collection it's still attached to the DataContext's context! Thus, if I try to update (I update by Attach()ing to the object and then SubmitChanges()) I get 开发者_StackOverflowthat dreaded "An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported." message.
Anyway, I'm starting to doubt that this technology was a good gamble. Has anyone got a decent architecture that they're willing to share? I'd really love to use this technology but I feel like I spend 1/3 of my time just debugging is retarded quirks!
The lifetime of a DataContext should be the lifetime of your "Unit of Work."
Example: Moving money from one account to another
This involves two steps, in an atomic transaction:
- Add money to the target account
- Subtract money from the source account
Your DataContext should not detach itself after step one. It should stay alive until both steps are completed.
I personally use DataContext only within the "using" blocks for all CRUD methods.
There is a simpler way to use Detach(). I use it only when I save an entity, updates work fine. There are few articles online on how to "Fix" that dreaded error that you have mentioned, but from my experience, when the DAL is properly designed you don't need to do that at all.
I also set the deferred loading so that it doesn't load any associated data and I work with one entity at a time, i.e. Order, Customer, Item.
When I save the order for multiple items I simple iterate through Items and call .Save() on each item method. Save method decides whether it's an updated or insert based on the Id of the object.
Also using timestamps for concurrency seems to be way easier and more efficient than comparing old and new objects.
If you're looking for an example, try StackOverflow!
For a peek into StackOverflow's LINQ To SQL model, check out this video from PDC 2008 at around 51:00.
精彩评论