public async Task UpdateFailsIfVersionNumberChanged() { using var db = new MockServerVersionDbContextUsingMutations(ConnectionString); // Set the result of the concurrency check to an empty result set to simulate a version number that has changed. var concurrencySql = $"SELECT 1 FROM `SingersWithVersion` {Environment.NewLine}WHERE `SingerId` = @p0 AND `Version` = @p1"; _fixture.SpannerMock.AddOrUpdateStatementResult(concurrencySql, StatementResult.CreateSingleColumnResultSet(new V1.Type { Code = V1.TypeCode.Int64 }, "COL1")); // Attach a singer to the context and try to update it. var singer = new SingersWithVersion { SingerId = 1L, FirstName = "Pete", LastName = "Allison", Version = 1L }; db.Attach(singer); singer.LastName = "Allison - Peterson"; await Assert.ThrowsAsync <DbUpdateConcurrencyException>(() => db.SaveChangesAsync()); // Update the concurrency check result to 1 to simulate a resolved version conflict. _fixture.SpannerMock.AddOrUpdateStatementResult(concurrencySql, StatementResult.CreateSelect1ResultSet()); Assert.Equal(1L, await db.SaveChangesAsync()); }
public async Task VersionNumberIsAutomaticallyGeneratedOnInsertAndUpdate() { using var db = new MockServerVersionDbContextUsingMutations(ConnectionString); var singer = new SingersWithVersion { SingerId = 1L, FirstName = "Pete", LastName = "Allison" }; db.Singers.Add(singer); await db.SaveChangesAsync(); Assert.Empty(_fixture.SpannerMock.Requests.Where(r => r is ExecuteBatchDmlRequest)); Assert.Collection( _fixture.SpannerMock.Requests.Where(r => r is CommitRequest).Select(r => r as CommitRequest), r => { Assert.Collection( r.Mutations, mutation => { Assert.Equal(Mutation.OperationOneofCase.Insert, mutation.OperationCase); Assert.Equal("SingersWithVersion", mutation.Insert.Table); Assert.Collection( mutation.Insert.Columns, column => Assert.Equal("SingerId", column), column => Assert.Equal("FirstName", column), column => Assert.Equal("LastName", column), column => Assert.Equal("Version", column) ); Assert.Collection( mutation.Insert.Values, row => Assert.Collection( row.Values, value => Assert.Equal("1", value.StringValue), value => Assert.Equal("Pete", value.StringValue), value => Assert.Equal("Allison", value.StringValue), value => Assert.Equal("1", value.StringValue) ) ); } ); } ); _fixture.SpannerMock.Reset(); // Update the singer and verify that the version number is first checked using a SELECT statement and then is updated in a mutation. var concurrencySql = $"SELECT 1 FROM `SingersWithVersion` {Environment.NewLine}WHERE `SingerId` = @p0 AND `Version` = @p1"; _fixture.SpannerMock.AddOrUpdateStatementResult(concurrencySql, StatementResult.CreateSelect1ResultSet()); singer.LastName = "Peterson - Allison"; await db.SaveChangesAsync(); Assert.Empty(_fixture.SpannerMock.Requests.Where(r => r is ExecuteBatchDmlRequest)); Assert.Collection( _fixture.SpannerMock.Requests.Where(r => r is ExecuteSqlRequest).Select(r => r as ExecuteSqlRequest), r => { Assert.Equal("1", r.Params.Fields["p0"].StringValue); // SingerId Assert.Equal("1", r.Params.Fields["p1"].StringValue); // Version } ); Assert.Collection( _fixture.SpannerMock.Requests.Where(r => r is CommitRequest).Select(r => r as CommitRequest), r => { Assert.Collection( r.Mutations, mutation => { Assert.Equal(Mutation.OperationOneofCase.Update, mutation.OperationCase); Assert.Equal("SingersWithVersion", mutation.Update.Table); Assert.Collection( mutation.Update.Columns, column => Assert.Equal("SingerId", column), column => Assert.Equal("LastName", column), column => Assert.Equal("Version", column) ); Assert.Collection( mutation.Update.Values, row => Assert.Collection( row.Values, value => Assert.Equal("1", value.StringValue), value => Assert.Equal("Peterson - Allison", value.StringValue), value => Assert.Equal("2", value.StringValue) ) ); } ); } ); }