Adrian Grigore

Linq entity Version property in databound controls

In LINQ on October 3, 2008 at 16:39

Since I am currently working on a multi-tier ASP.NET application, I frequently have to display Linq entities in data-driven controls such as GridView, DetailView, etc.

Most of my Linq entities have a version attribute to speed up database operations, and sometimes the entities are not only displayed, but also updated and saved back to the database. The first time I tried this, I got the following exception:

A first chance exception of type ‘System.Data.Linq.ChangeConflictException’ occurred in System.Data.Linq.dll

The reason for this is that I was not displaying the version anywhere in the Detailsview. When saving the entity back to the database, the ObjectDataSource created a new entity with default values for all properties that were not bound to any datafields in the DetailsView. So, the entity was re-instantiated with Version==null and when trying to update the database table for the Linq entity, Linq was looking for a row with a 0 version column.

I thought I might work around this by simply version property of the Linq entity to an invisible Column in the Detailsview. But that only gave me a new exception when trying to update the entity:

Sytem. InvalidOperationException: Cannot convert value of parameter ‘Version’ from ‘System.String’ to ‘System.Data.Linq.Binary’

The reason for this is that the Version attribute in Linq entities is of the type System.Data.Linq.Binary, which can be converted to a string, but not back from string to System.Data.Linq.Binary.

It took me quite a while to find at least some workaround for this problem. A working – but somewhat awkward – solution is to create a VersionString propery in each entity:

 public partial class Customer
 {
 public string VersionString
 {
 get { return _Version.TimestampToString(); }
 set { _Version = value.StringToTimestamp(); }
 }
 }

public static class DateTimeExtensions
 {
 public static string TimestampToString(this Binary binary)
 {
 return Convert.ToBase64String(binary.ToArray());
 }
 public static Binary StringToTimestamp(this string s)
 {
 return new Binary(Convert.FromBase64String(s));
 }
 }

Then I bound the VersionString to a hidden field in the DetailsView and the problem was gone. But this solution is not ideal since it requires the VersionString property to be defined for every single Linq entity type that uses a timestamp.

But wait, there’s a much easier way, I stumbled across this solution while playing around with Detailsview a few days ago: Simply add the Version propery to the DataKeyNames property of the DetailsGrid. For example, if your DataKeyNames propery is usually DataKeyNames=”ID”, write DataKeyNames=”ID,Version” instead.

This way the DetailsView serializes the Version property to it’s view state and deserializes it again when the entity has to be recreated. No need to fiddle with the VersionString approach above.

Advertisements
  1. Hey, thank you for your post. luckily i am not the only one with this problem. i tried your solution, the short way with the DataKeyNames, but it still won’t work. Are you sure you did not change anything else ?
    thank you for your help !

  2. Yes, I’m quite sure about that. I’ve sent you a demo project that shows this in action. Hopefully it will help you circumvent this nasty problem 🙂

  3. Thanks very much for posting this. A quick-and-easy solution that just works!
    BTW, if you are using SQLMetal to generate your LINQ classes, you could let them inherit from a base class, and define any common methods or properties in there.
    Regardless, solution 2 is quicker! Thanks again

  4. […] intends to write mainly about software development on this site. His exciting first topic is ‘Linq entity Version property in databound controls‘. I kid you not – click on the link and check it […]

  5. Herzlichen Glückwunsch zum ersten Artikel!

Comments are closed.

%d bloggers like this: