Uncategorized

RIA Services and Timestamp/Concurrency Field Gotcha

I’m working with a table that has a timestamp column in EF. I’m using this to detect when multiple people are editing the same data so that one person’s changes don’t get overwritten by another user. In the EF designer, you would mark this property as StoreGeneratedPattern=Computed and ConcurrencyMode=Fixed, so that the code gen knows to generate a read-only field that gets roundtripped to the server on updates. If, during an update, the timestamp value that gets roundtripped to the server differs from the one in the database, then an OptimisticConcurrencyException is thrown so you have a chance to get the stored version of the data and possibly pop up a dialog that allows you to merge the changes together.

However, I have come across a gotcha when working with RIA services. Since the timestamp field is not NULLable, RIA services marks it as [Required] and [Editable(false)] when generating the code. When creating a new class to add to the data store, this ends up messing with validation, so in my datagrid it pops up with “Timestamp field is required”. You can’t set the field yourself, as it will throw an exception saying that the field is read-only.

A solution is found in the comments here for Linq-to-SQL, so here’s how to do it for EF.

I didn’t bother using the EF designer, I right-clicked the file in VS and clicked “Open With…”, then clicked XML editor. This brings up the XML schema that’s used to generate all of the code. Scroll down until you can find the class, mine was <EntityType Name="Class">. Find the property for your timestamp, mine was <PropertyType Name="Timestamp" ConcurrencyMode="Fixed" Nullable="false" ...>. Change that Nullable="false" to true, and save. The RIA services generated code will no longer require you to fill in the timestamp, and the database will handle creating the timestamp for you when the object is persisted to the database.

However, there is one more gotcha – it’s still marked as a required field. There may be a better way to accomplish this, but what I did was this: I have a field called CreationTimestamp, so I used the partial OnCreationTimestamp() method:

partial void OnCreationTimestampChanged()
{
if (Timestamp == null)
Timestamp = new byte[] { };
}

This fixes the issue, for now.

Anyone know of a better way?

2 thoughts on “RIA Services and Timestamp/Concurrency Field Gotcha

  1. Very easy, after trying and trying for two days. I discovered the following.
    I’m using Silvelight 5, RIA, Entity Framework 5 and my model is Code First:

    public class Destination
    {
    public int DestinationId { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
    public string Description { get; set; }
    public byte[] Photo { get; set; }
    public List Lodgings { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; }

    }

    The trick is using Fluent API

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    modelBuilder.Configurations.Add(new ProductDestination());
    }

    }

    internal class ProductDestination : EntityTypeConfiguration
    {
    public ProductDestination()
    {
    this.Property(t => t.RowVersion)
    .IsOptional(); //Here the trick
    }
    }

    Now you can create a new record and saved it without getting the error rowversion is required or timespam field is required.
    Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s