Owned Entities should not be allowed a concurrency token to be defined

XMLWordPrintableJSON

    • Type: Improvement
    • Resolution: Done
    • Priority: Unknown
    • 10.0.3, 9.1.3, 8.4.3
    • Affects Version/s: None
    • Component/s: None
    • None
    • None
    • Dotnet Drivers
    • None
    • None
    • None
    • None
    • None
    • None

      Due to the way UpdateOne and DeleteOne only allow for a single filter and not per-document subfilters we can not support concurrency tokens on owned entities. The only way to do it otherwise would be to perform multiple update/delete passes over the documents (with some re-ordering of operations too).

      Unfortunately today we do not prevent them from being defined so the model can declare a concurrency token on an owned entity and then it is silently ignored.

      We should flag such kinds of invalid concurrency tokens at model validation time to prevent unexpected behavior.

        class Order
        {
            public ObjectId _id { get; set; }
            public string Name { get; set; }
            public Audit Audit { get; set; }   // owned (nested) entity
        }
      
        class Audit
        {
            [ConcurrencyCheck]          // token lives on the owned entity, not the root
            public int Version { get; set; }
            public string Text { get; set; }
        }
      
        // 1. Seed
        using (var db1 = /* context */)
        {
            db1.Add(new Order { Name = "Root", Audit = new Audit { Version = 1, Text = "Initial" } });
            db1.SaveChanges();
        }
      
        // 2. A concurrent context advances the owned token
        using (var db2 = /* fresh context */)
        {
            var o = db2.Set<Order>().First();
            o.Audit.Version = 2;
            o.Audit.Text = "Changed by db2";
            db2.SaveChanges();
        }
      
        // 3. A stale context (still sees Audit.Version == 1) edits the owned entity and saves
        order1.Audit.Text = "Changed by db1";
        db1.SaveChanges();   // EXPECTED: DbUpdateConcurrencyException
                             // ACTUAL:   succeeds and overwrites db2's changeç

      Expected: step 3 throws DbUpdateConcurrencyException (the update filter should include { "Audit.Version": 1 }, match nothing).

      Actual: the save succeeds; a re-read shows Audit.Text == "Changed by db1", proving the owned token was never checked.

            Assignee:
            Damien Guard
            Reporter:
            Damien Guard
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: