locked
Entity Framework + WCF Data Service + Concurrency RRS feed

  • Question

  • So I've created a WCF Data Service with a Customer POCO entity with a Timestamp column. The column is of type "timestamp" in the database, and concurrency mode = Fixed, Type = Binary and Store Generated Pattern = Computed in Entity Framework. If I go directly through the Entity Framework (e.g. skip the WCF Data Service I've created) in my test WPF GUI, I get the OptimisticConcurrencyException I expect when I change the data 2 places. However...when I do the same through the WCF Data Service, the last one who saves "wins". I get no exception at all. The collection is tracked, I've tried every combination of MergeOptions I think...still it doesn't seem to work. I thought this was pretty easy to achieve...but seems to be more to it. Here is the testcode if anyone can point out what's wrong.

    ModelContainer ctx1 = new ModelContainer(new Uri("http://localhost/IISEFWeb/EntityDataService.svc/"));
          ModelContainer ctx2 = new ModelContainer(new Uri("http://localhost/IISEFWeb/EntityDataService.svc/"));
          
          // Download and change some data
          var s = ctx1.Customers.ToList();
          s[0].Name = s[0].Name + "_A";
          s[1].Name = s[1].Name + "_B";
          var n = new Customer() { Name = (s.Count + 100).ToString() };
          ctx1.AddToCustomers(n);
          ctx1.UpdateObject(s[0]);
          ctx1.UpdateObject(s[1]);
    
          // Using separate context, change some data - this will invalidate etags on the changed entities in ctx1
          var s2 = ctx2.Customers.ToList();
          s2[0].Name = s2[0].Name + "_2A";
          ctx2.UpdateObject(s2[0]);
          ctx2.SaveChanges();
    
          // And now try the operation which should fail (due to etag mismatch)
          try
          {
            var b = ctx1.SaveChanges();
            Console.WriteLine(b);
          }
          catch (DataServiceRequestException exception)
          {
            foreach (ChangeOperationResponse response in exception.Response)
            {
              Console.WriteLine(((Customer)((EntityDescriptor)response.Descriptor).Entity).CustomerId + ": " + (response.Error == null ? "Success" : response.Error.Message));
            }
          }
    

    Monday, November 8, 2010 3:25 PM

Answers

  • OK, Turns out that Espen is using POCO EF entities, which has a known issue with Dev 10 Data Services. Here's the hotfix that addresses this issue:

     

    http://support.microsoft.com/kb/2277657

     

    Regards,

    PQ


    Peter Q. http://blogs.msdn.com/peter_qian
    Thursday, November 11, 2010 11:30 PM
    Answerer

All replies

  • Hi,

    Did you use Code-Gen to generate the client side code? What does your Customers type look like?

    Can you capture the trace using fiddlers tool, and see if the If-Match header is sent correct?

    Regards,

    PQ


    Peter Q. http://blogs.msdn.com/peter_qian
    Monday, November 8, 2010 9:29 PM
    Answerer
  • I've done model first, but I've changed the DDL template to create the Timestamp column as type typestamp in the database.

    DB table

     

    USE [TestDb]
    GO
    
    /****** Object: Table [dbo].[Customers] Script Date: 11/09/2010 10:39:35 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [dbo].[Customers](
    	[CustomerId] [int] IDENTITY(1,1) NOT NULL,
    	[Name] [nvarchar](max) NOT NULL,
    	[Timestamp] [timestamp] NOT NULL,
     CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
    (
    	[CustomerId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    

     

    Customer class:

     

    public partial class Customer: StateObject
     {
      #region Primitive Properties
     
      public int CustomerId
      {
       get;
       set;
      }
     
      public string Name
      {
       get;
       set;
      }
     
      public byte[] Timestamp
      {
       get;
       set;
      }
    
      #endregion
      #region Navigation Properties
     
      public FixupCollection<Order> Orders
      {
       get
       {
        if (_orders == null)
        {
         var newCollection = new FixupCollection<Order>();
         newCollection.CollectionChanged += FixupOrders;
         _orders = newCollection;
        }
        return _orders;
       }
       set
       {
        if (!ReferenceEquals(_orders, value))
        {
         var previousValue = _orders as FixupCollection<Order>;
         if (previousValue != null)
         {
          previousValue.CollectionChanged -= FixupOrders;
         }
         _orders = value;
         var newValue = value as FixupCollection<Order>;
         if (newValue != null)
         {
          newValue.CollectionChanged += FixupOrders;
         }
        }
       }
      }
      private FixupCollection<Order> _orders;
    
      #endregion
      #region Association Fixup
     
      private void FixupOrders(object sender, NotifyCollectionChangedEventArgs e)
      {
       if (e.NewItems != null)
       {
        foreach (Order item in e.NewItems)
        {
         item.Customer = this;
        }
       }
     
       if (e.OldItems != null)
       {
        foreach (Order item in e.OldItems)
        {
         if (ReferenceEquals(item.Customer, this))
         {
          item.Customer = null;
         }
        }
       }
      }
    
      #endregion
     }
    

     

    Requestheader:

    MERGE http://zeus/IISEFWeb/EntityDataService.svc/Customers(2) HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 2.0;NetFx
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    Content-Type: application/atom+xml
    If-Match: W/"X'0000000000002F83'"
    Host: zeus
    Content-Length: 785
    Expect: 100-continue
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
     <category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" term="Model.Customer" />
     <title />
     <author>
      <name />
     </author>
     <updated>2010-11-09T10:08:41.0566406Z</updated>
     <id>http://zeus/IISEFWeb/EntityDataService.svc/Customers(2)</id>
     <content type="application/xml">
      <m:properties>
       <d:CustomerId m:type="Edm.Int32">2</d:CustomerId>
       <d:Name>329_B_B_B_B_B_B_B_B</d:Name>
       <d:Timestamp m:type="Edm.Binary">AAAAAAAAL4M=</d:Timestamp>
      </m:properties>
     </content>
    </entry>

    Responseheader

    HTTP/1.1 204 No Content
    Cache-Control: no-cache
    ETag: W/"X'0000000000002F87'"
    Server: Microsoft-IIS/7.5
    DataServiceVersion: 1.0;
    X-AspNet-Version: 4.0.30319
    X-Powered-By: ASP.NET
    Date: Tue, 09 Nov 2010 10:08:41 GMT

     

    It's really just a testproject...but looks like it sends the correct merge operation at least. It just seems like the If-Match ETag isn't evaluated at all. The headers are from the call that should fail by the way.

    Tuesday, November 9, 2010 10:04 AM
  • Interesting...AFAIK the Etags work out of the box with EF.

    Maybe you can create a simple repro project and send it to me? (pqian at microsoft dot com)

    Also, what version of EF/WCF Data Service are you using?

     


    Peter Q. http://blogs.msdn.com/peter_qian
    Tuesday, November 9, 2010 10:23 PM
    Answerer
  • Well...that's what I thought as well! To be honest...it seems like it doesn't work at all (I've tried with both silverlight 4 and WPF).

    Emailed you a testproject. You should've received it from bergespe at online.no.

    As for my setup:

    Entity Framework 4.0

    WCF Data Service 2.0? (not exactly sure, using the one that shipped with Visual Studio 2010 Ultimate)

    Windows 7 Enterprise x64

    Visual Studio 2010 Ultimate

     

    Pretty much the newest of everything afaik. No betas installed and everything should be patched.

    Wednesday, November 10, 2010 9:38 AM
  • OK, Turns out that Espen is using POCO EF entities, which has a known issue with Dev 10 Data Services. Here's the hotfix that addresses this issue:

     

    http://support.microsoft.com/kb/2277657

     

    Regards,

    PQ


    Peter Q. http://blogs.msdn.com/peter_qian
    Thursday, November 11, 2010 11:30 PM
    Answerer
  • How to download this hotfix? which the direct link?

     

    Thanks 


    Kássio
    Monday, November 29, 2010 1:29 AM