Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concurrency using xmin #179

Closed
flipchart opened this issue Apr 21, 2017 · 2 comments
Closed

Concurrency using xmin #179

flipchart opened this issue Apr 21, 2017 · 2 comments

Comments

@flipchart
Copy link

I'm trying to use optimistic concurrency using xmin, but I'm not getting any exceptions thrown when the specified xmin value is "incorrect" (i.e. not what is in the DB).

See the gist here and note line 27

I've logged the SQL for the statement and it does contain an appropriate WHERE clause on the xmin value, however, I can't seem to log the parameter values, and I suspect that the loaded xmin value is being sent to the DB, rather than the value (1) that I specify.

Am I doing something wrong?

@flipchart
Copy link
Author

Apologies! This is an EF issue (as seen with the other providers). It's due to loading the entity, rather than attaching a newly constructed one

@mikylebaksh
Copy link

mikylebaksh commented Feb 28, 2019

I wanted to expand on this.

To anyone coming here in the future, the correct way to verify concurrency is to follow the answer here: https://stackoverflow.com/a/47480552

In other words, to correct the linked gist by @flipchart:

using System;
using Microsoft.EntityFrameworkCore;

namespace DataSetSerialization
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var fooId = Guid.NewGuid();

            using (var context = new TestContext())
            {
                context.Add(new Person
                {
                    Id = fooId,
                    Name = "Foo",
                });

                context.SaveChanges();
            }

            using (var context = new TestContext())
            {
                var wes = context.Find<Person>(fooId);
                wes.Name = "Bar";

                context.Entry(wes).Property(x => x.XMin).OriginalValue = (uint) 1;

                // context.SaveChanges throws DbUpdateConcurrencyException
                context.SaveChanges();
            }
        }
    }

    internal class TestContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseNpgsql("User ID=postgres;Password=xxxx;Host=localhost;Port=5432;Database=test;Pooling=true;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Person>(b =>
            {
                b.Property(x => x.XMin)
                    .HasColumnName("xmin")
                    .HasColumnType("xid")
                    .ValueGeneratedOnAddOrUpdate()
                    .IsConcurrencyToken();
            });

            base.OnModelCreating(modelBuilder);
        }
    }

    public class Person
    {
        public Guid Id { get; set; }
        public string Name { get; set; }

        public uint XMin { get; set; }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants