Concurrency issue using Db.Save(model, true)

I have a table that have many 1:1 relation define (see bottom)

On my service side I call Db.Save(audit, true);

When I try to assign more then one reference I got the exception:
ServiceStack.WebServiceException : Exception of type ‘ServiceStack.Data.OptimisticConcurrencyException’

When I query my table from SSMS I see my result in Audit, ManureResult and RumenFillResult

Why I have a concurrency issue my 3 records are new so the Save should not try to validate rowversion property ?

My assignment:

			var fr = new FarmsRequest();
                        var frResponse = client.Get(fr);
            
			var request = new SyncAuditRequest();

			var audit = new Audit();

			audit.Name = "FakeSync";
			audit.FlatStage = "FakeSync";
			audit.MainType = "FakeSync";
			audit.AnimalNb = "200";
			audit.AnimalAge = "9";
			audit.AnimalSex = "male";
			audit.AnimalDietType = "Normal";
			audit.Date = System.DateTime.UtcNow;
			audit.State = "Fine";
			audit.Progress = 60;
			audit.Score = "60";
			audit.Benchmark = "FakeTest";
			audit.FarmId = frResponse.Farms[0].FarmId; 

			//var dietResult = new DietResult();
			//dietResult.AccessFiber = 15;
			//dietResult.MainFiber = 12;
			//dietResult.FiberQuality = 20;
			//dietResult.FiberRegularity = 35;
			//dietResult.ValidCategory = true;
			//audit.DietResult = dietResult;

		var manureResult = new ManureResult();
		manureResult.Medium = "5";
		manureResult.Pasty = "3";
		manureResult.Liquid = "0";
		audit.ManureResult = manureResult;

                    var rumenFillResult = new RumenFillResult();
                    rumenFillResult.Normal = "10";
                    rumenFillResult.SlightlyEmpty = "1";
                    rumenFillResult.Bloated = "2";
                    audit.RumenFillResult = rumenFillResult;

                    request.Audit = audit;
                    var response = client.Post(request);

My definition Poco:

[Schema("REIBeef")] //Specifique to REIBeef
    public class Audit : AuditBOFields, IAudit, IConcurrency
    {
        [PrimaryKey,AutoIncrement]
        public int? AuditId { get; set; }
        public string Name { get; set; }
        public string FlatStage { get; set; }
        public string MainType { get; set; }
        public string AnimalNb { get; set; }
        public string AnimalAge { get; set; }
        public string AnimalSex { get; set; }
        public string AnimalDietType { get; set; }
        public DateTime Date { get; set; }
        public string State { get; set; }
        public double Progress { get; set; }
        public string Score { get; set; }
        public string Benchmark { get; set; }
        public string Vignet { get; set; }
        public string Comment { get; set; }

		[References(typeof(Farm)),]
        public int? FarmId { get; set; }
		[Reference]
		public Farm Farm { get; set; }

		[References(typeof(DietResult))]
		public int? DietId { get; set; }
		[Reference]
        public DietResult DietResult { get; set; }
        
		[References(typeof(ManureResult))]
        public int? ManureId { get; set; }
        [Reference]
        public ManureResult ManureResult { get; set; }

		[References(typeof(RumenFillResult))]
        public int? RumenId { get; set; }
 		[Reference]
        public RumenFillResult RumenFillResult { get; set; }
        
		[References(typeof(FacilitiesResult))]
		public int? FacilityId { get; set; }
		[Reference]
        public FacilitiesResult FacilitiesResult { get; set; }

		[References(typeof(CleanlinessResult))]
		public int? CleanId { get; set; }
		[Reference]
        public CleanlinessResult CleanlinessResult { get; set; }
        
		[References(typeof(FeetInflamationResult))]
		public int? FeetId { get; set; }
        [Reference]
        public FeetInflamationResult FeetInflamationResult { get; set; }

		[References(typeof(HornsInflamationResult))]
		public int? HornsInflamationRowId { get; set; }
		[Reference]
        public HornsInflamationResult HornsInflamationResult { get; set; }

		[References(typeof(AnimalPerformanceResult))]
		public int? ApId { get; set; }
		[Reference]
        public AnimalPerformanceResult AnimalPerformanceResult { get; set; }

		[References(typeof(TemperaturehumidityResult))]
		public int? TempId { get; set; }
		[Reference]
        public TemperaturehumidityResult TemperaturehumidityResult { get; set; }

		[References(typeof(BehaviourObservationsResult1))]
		public int? Bo1Id { get; set; }
		[Reference]
        public BehaviourObservationsResult1 BehaviourObservationsResult1 { get; set; }

		[References(typeof(BehaviourObservationsResult2))]
        public int? Bo2Id { get; set; }
		[Reference]
        public BehaviourObservationsResult2 BehaviourObservationsResult2 { get; set; }
        
        public ulong RowVersion { get; set; }
    }
}

if I replace Db.Save like this:

	    var response = new SyncAuditResponse();
	    var rumenId = Db.Insert(request.Audit.RumenFillResult, true);
	    var manureid = Db.Insert(request.Audit.ManureResult, true);
	    var dietid = Db.Insert(request.Audit.DietResult, true);
	    request.Audit.RumenId = (int)rumenId;
	    request.Audit.ManureId = (int)manureid;
	    request.Audit.DietId= (int)dietid;
	    var auditid = Db.Insert(request.Audit, true);

	    Db.LoadReferences(request.Audit);

	    //Db.Save(request.Audit, true);

It work and my LoadReferences work to.

Interesting…

If I assign only one of my many 1:1 relation Db.Save() Work OK…

I can’t tell from here, if you can put together a small stand-alone example that repro’s the issue I can have a look, either on Gistlyn or in a GitHub project I can run locally to repro the issue.

OK I will do it. maybe during the repro. I will also find my error.

I was able to reproduce the issue.
With SQLite and :Memory: but it’s different exception I put comment in program.cs

static OrmLiteConnectionFactory dbFactory;
static System.Data.IDbConnection db;
protected static void Main(string[] args)
{
	dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
	//dbFactory = new OrmLiteConnectionFactory("repro.sqlite", SqliteDialect.Provider);
    db = dbFactory.Open();    
	ResetSchema();
    
	var audit = new Audit();

    audit.Name = "FakeSync";
    audit.FlatStage = "FakeSync";
    audit.MainType = "FakeSync";
    audit.AnimalNb = "200";
    audit.AnimalAge = "9";
    audit.AnimalSex = "male";
    audit.AnimalDietType = "Normal";
    audit.Date = System.DateTime.UtcNow;
    audit.State = "Fine";
    audit.Progress = 60;
    audit.Score = "60";
    audit.Benchmark = "FakeTest";

    // This one only it work no exception
    var dietResult = new DietResult();
    dietResult.AccessFiber = 15;
    dietResult.MainFiber = 12;
    dietResult.FiberQuality = 20;
    dietResult.FiberRegularity = 35;
    dietResult.ValidCategory = true;
    audit.DietResult = dietResult;

	// With this one included 'ServiceStack.Data.OptimisticConcurrencyException'
    var manureResult = new ManureResult();
    manureResult.Medium = "5";
    manureResult.Pasty = "3";
    manureResult.Liquid = "0";
    audit.ManureResult = manureResult;

	// With this one included When using SQLite = "SQLite Error 19: 'FOREIGN KEY constraint failed'."
	// When run :memory: 'ServiceStack.Data.OptimisticConcurrencyException'
	var rumenFillResult = new RumenFillResult();
    rumenFillResult.Normal = "10";
    rumenFillResult.SlightlyEmpty = "1";
    rumenFillResult.Bloated = "2";
    audit.RumenFillResult = rumenFillResult;

	db.Save(audit, true);

Thanks for the repro, multiple self references with RowVersion should be resolved from this commit.

This change is available from v5.1.1 that’s now available on MyGet.

1 Like

Work like a charm :slight_smile:

Thanks!