Major Design Flaw in LINQ to SQL?
-
Thursday, October 02, 2008 1:32 AMI've been beating my head about how to implement a simple scenario using LINQ to SQL without success.
This example is not my actual scenario but a simplification to describe something which I believe should be straightforward to implement.
Suppose you have an entity called "Customer". This entity has an EntitySet associated with it called "Addresses". Now, you are creating a windows application to edit the customer's information including their addresses. On the first form you have a list of customers. Clicking on a customer displays their current information, including their list of addresses in a read-only manner. You have buttons to add, delete or edit the currently selected customer on this form. Clicking on add or edit brings up a new form, the customer editor form. This form lets you edit all the information about the customer including their list of addresses. On both forms, you are using data binding to bind directly to the entity's properties.
Now, how to implement this scenario using LINQ to SQL? Should you use one DataContext for both forms or a separate DataContext for each form?
Let's first look at using one DataContext for both forms. The problem with this method is that if the user cancels the customer editor form, you need to "revert" any changes made to the Customer entity. One method is to use DataContext.Refresh() with a RefreshMode of OverwriteCurrentValues. This works fine for the Customer entity itself, but what if the user added or removed Address entities in the Addresses EntitySet? There is no way to 'revert' or 'reload' the EntitySet. You could potentially manually do this, but since object tracking is enabled on the DataContext, adding or removing items from the EntitySet will trigger updates to the DB on the next call to SubmitChanges().
Now how about using a separate DataContext for each form. This solves the cancel problem as all edits are performed under a different context, however this causes the opposite problem on the main form in how do you update an edited customer? Again, you can use DataContext.Refresh() for the Customer entity but then you run into the same issue in that there is no good way to refresh the Addresses EntitySet.
Is there something I'm missing or is there an easy way to solve this dilema?
Seems to me there really needs to be a Refresh() method on the EntitySet. Alternatively, something like RejectChanges() on the DataContext which would revert all entities back to their original state.
All Replies
-
Thursday, October 02, 2008 4:49 AM
Hi
As i know it is really better to use diffrent datacontext.
but for your problem about refresh customer details(Addresses) you can use Refresh Method also, after user save changes in the dilog form :
db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer);
db.Refresh(RefreshMode.OverwriteCurrentValues, customer.Addresses);
I hope this was helpful. -
Thursday, October 02, 2008 6:09 PMYes, this method would update any existing addresses that were edited, but if the user added or removed addresses this call would not update the EntitySet accordingly.
-
Sunday, October 05, 2008 4:41 AMHI
As I know you should query database for retrieving the addresses of selected Customer.
this.addressBindingSource.DataSource = db.addresses.Where(c => c.Customer == customer); -
Tuesday, October 07, 2008 5:58 PMI know but this kind of defeats the purpose of defining entitiy relationships in your data model. Why have entity relationships at all if you have to query them manually?
-
Sunday, March 01, 2009 10:10 AMHello Jef,
I do not have a solution for you, but I have the same problem. So if you find any solution for that I will be thankful if you can send it to me.
shyossy@gmail.com
Yossy -
Friday, May 01, 2009 10:27 AMEnterprise Application Architecture with LINQ to SQL
http://www.codeproject.com/KB/architecture/EnterpriseApplicationArch.aspx?msg=2256835#xx2256835xx -
Monday, May 04, 2009 6:37 AMHi Jeff,
Initially (in the May 2006 CTP of LINQ ), the RejectChanges was there, but later the same had been removed from the LINQ framework. See http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/177e5899-1aec-4754-9df2-ba30fca4da7a/
But you can acheive this manuall by calling GetOriginalEntityState method (http://msdn.microsoft.com/en-us/library/bb548700.aspx). This will return you original state of an entity since it was either created or attached to the current datacontext.
customerObj = dataContext.GetTable<Customer>().GetOriginalEntityState(cusomterObj);
However, it only copies primitive values, not associations. Say in the problem which you posted "Addresses" entity is an assosciation, so that won't be reset to the orginal state when you call the GetOriginalEntityState for Customer Object. If you want to reset only the primitive type and load the associations manually then you can use GetOriginalEntityState.
But if you want to have a revert method which revert even the assications, then you need to implement your own logic (with deep copy logic) and made this as an extension method, which you can use with other table objects.
Thanks and regards,
Vijay Pandurangan- Edited by Vijay PanduranganMicrosoft Employee Monday, May 04, 2009 6:39 AM

