diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs index 5e94d32626a..fbcfbde6d85 100644 --- a/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs +++ b/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs @@ -237,6 +237,19 @@ private static bool IsConcurrencyConflict( var comparer = property.GetKeyValueComparer(); var originalValue = entry.GetOriginalValue(property); + var useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue23527", out var enabled) && enabled; + + if (!useOldBehavior) + { + var converter = property.GetValueConverter() + ?? property.FindTypeMapping()?.Converter; + + if (converter != null) + { + rowValue = converter.ConvertFromProvider(rowValue); + } + } + if ((comparer != null && !comparer.Equals(rowValue, originalValue)) || (comparer == null && !StructuralComparisons.StructuralEqualityComparer.Equals(rowValue, originalValue))) { diff --git a/test/EFCore.InMemory.FunctionalTests/F1InMemoryFixture.cs b/test/EFCore.InMemory.FunctionalTests/F1InMemoryFixture.cs index 2f7ab6982fb..fe36a5a4141 100644 --- a/test/EFCore.InMemory.FunctionalTests/F1InMemoryFixture.cs +++ b/test/EFCore.InMemory.FunctionalTests/F1InMemoryFixture.cs @@ -1,16 +1,28 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.TestUtilities; namespace Microsoft.EntityFrameworkCore { - public class F1InMemoryFixture : F1FixtureBase + public class F1InMemoryFixture : F1InMemoryFixtureBase + { + } + + public class F1ULongInMemoryFixture : F1InMemoryFixtureBase + { + } + + public abstract class F1InMemoryFixtureBase : F1FixtureBase { public override TestHelpers TestHelpers => InMemoryTestHelpers.Instance; protected override ITestStoreFactory TestStoreFactory => InMemoryTestStoreFactory.Instance; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + => base.AddOptions(builder).ConfigureWarnings(e => e.Ignore(InMemoryEventId.TransactionIgnoredWarning)); } } diff --git a/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs b/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs index d7a25ad1621..cc4a31b69c5 100644 --- a/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs @@ -14,7 +14,6 @@ public class InMemoryComplianceTest : ComplianceTestBase { // No in-memory tests typeof(FunkyDataQueryTestBase<>), - typeof(OptimisticConcurrencyTestBase<>), typeof(StoreGeneratedTestBase<>), typeof(ConferencePlannerTestBase<>), typeof(ManyToManyQueryTestBase<>), diff --git a/test/EFCore.InMemory.FunctionalTests/OptimisticConcurrencyInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/OptimisticConcurrencyInMemoryTest.cs new file mode 100644 index 00000000000..3f9b2465027 --- /dev/null +++ b/test/EFCore.InMemory.FunctionalTests/OptimisticConcurrencyInMemoryTest.cs @@ -0,0 +1,92 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.EntityFrameworkCore +{ + public class OptimisticConcurrencyULongInMemoryTest : OptimisticConcurrencyInMemoryTestBase + { + public OptimisticConcurrencyULongInMemoryTest(F1ULongInMemoryFixture fixture) + : base(fixture) + { + } + } + + public class OptimisticConcurrencyInMemoryTest : OptimisticConcurrencyInMemoryTestBase + { + public OptimisticConcurrencyInMemoryTest(F1InMemoryFixture fixture) + : base(fixture) + { + } + } + + public abstract class OptimisticConcurrencyInMemoryTestBase + : OptimisticConcurrencyTestBase + where TFixture : F1FixtureBase, new() + { + protected OptimisticConcurrencyInMemoryTestBase(TFixture fixture) + : base(fixture) + { + } + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Simple_concurrency_exception_can_be_resolved_with_store_values() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Simple_concurrency_exception_can_be_resolved_with_client_values() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Simple_concurrency_exception_can_be_resolved_with_new_values() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Simple_concurrency_exception_can_be_resolved_with_store_values_using_equivalent_of_accept_changes() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Simple_concurrency_exception_can_be_resolved_with_store_values_using_Reload() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Updating_then_deleting_the_same_entity_results_in_DbUpdateConcurrencyException() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task + Updating_then_deleting_the_same_entity_results_in_DbUpdateConcurrencyException_which_can_be_resolved_with_store_values() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task + Change_in_independent_association_after_change_in_different_concurrency_token_results_in_independent_association_exception() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Change_in_independent_association_results_in_independent_association_exception() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Two_concurrency_issues_in_one_to_many_related_entities_can_be_handled_by_dealing_with_dependent_first() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] + public override Task Two_concurrency_issues_in_one_to_one_related_entities_can_be_handled_by_dealing_with_dependent_first() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Throw DbUpdateException or DbUpdateConcurrencyException for in-memory database errors #23569")] + public override Task Adding_the_same_entity_twice_results_in_DbUpdateException() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Throw DbUpdateException or DbUpdateConcurrencyException for in-memory database errors #23569")] + public override Task Deleting_the_same_entity_twice_results_in_DbUpdateConcurrencyException() + => Task.FromResult(true); + + [ConditionalFact(Skip = "Throw DbUpdateException or DbUpdateConcurrencyException for in-memory database errors #23569")] + public override Task Deleting_then_updating_the_same_entity_results_in_DbUpdateConcurrencyException() + => Task.FromResult(true); + } +} diff --git a/test/EFCore.Relational.Specification.Tests/F1RelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/F1RelationalFixture.cs index 02d6de5ba59..259e40519fa 100644 --- a/test/EFCore.Relational.Specification.Tests/F1RelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/F1RelationalFixture.cs @@ -7,7 +7,7 @@ namespace Microsoft.EntityFrameworkCore { - public abstract class F1RelationalFixture : F1FixtureBase + public abstract class F1RelationalFixture : F1FixtureBase { public TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; diff --git a/test/EFCore.Relational.Specification.Tests/PropertyEntryTestBase.cs b/test/EFCore.Relational.Specification.Tests/PropertyEntryTestBase.cs index 44ecb4406f4..b8acf26c2ce 100644 --- a/test/EFCore.Relational.Specification.Tests/PropertyEntryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/PropertyEntryTestBase.cs @@ -10,7 +10,7 @@ namespace Microsoft.EntityFrameworkCore { public abstract class PropertyEntryTestBase : IClassFixture - where TFixture : F1FixtureBase, new() + where TFixture : F1FixtureBase, new() { protected PropertyEntryTestBase(TFixture fixture) => Fixture = fixture; diff --git a/test/EFCore.Specification.Tests/DatabindingTestBase.cs b/test/EFCore.Specification.Tests/DatabindingTestBase.cs index f8beeac7c06..dc5204aa30b 100644 --- a/test/EFCore.Specification.Tests/DatabindingTestBase.cs +++ b/test/EFCore.Specification.Tests/DatabindingTestBase.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore { public abstract class DatabindingTestBase : IClassFixture - where TFixture : F1FixtureBase, new() + where TFixture : F1FixtureBase, new() { protected DatabindingTestBase(TFixture fixture) => Fixture = fixture; diff --git a/test/EFCore.Specification.Tests/F1FixtureBase.cs b/test/EFCore.Specification.Tests/F1FixtureBase.cs index c2e95c3cfd1..b3dd0d2f17f 100644 --- a/test/EFCore.Specification.Tests/F1FixtureBase.cs +++ b/test/EFCore.Specification.Tests/F1FixtureBase.cs @@ -8,7 +8,7 @@ namespace Microsoft.EntityFrameworkCore { - public abstract class F1FixtureBase : SharedStoreFixtureBase + public abstract class F1FixtureBase : SharedStoreFixtureBase { protected override string StoreName { get; } = "F1Test"; @@ -90,6 +90,43 @@ protected virtual void BuildModelExternal(ModelBuilder modelBuilder) .HasOne(t => t.Team) .WithMany()) .HasKey(ts => new { ts.SponsorId, ts.TeamId }); + + modelBuilder.Entity().Property("Version").IsRowVersion(); + modelBuilder.Entity().Property("Version").IsRowVersion(); + + modelBuilder.Entity().Property("Version") + .ValueGeneratedOnAddOrUpdate() + .IsConcurrencyToken(); + + modelBuilder.Entity( + eb => + { + eb.Property("Version").IsRowVersion(); + eb.Property(Sponsor.ClientTokenPropertyName); + }); + + modelBuilder.Entity() + .OwnsOne( + s => s.Details, eb => + { + eb.Property(d => d.Space); + eb.Property("Version").IsRowVersion(); + eb.Property(Sponsor.ClientTokenPropertyName).IsConcurrencyToken(); + }); + + if (typeof(TRowVersion) != typeof(byte[])) + { + modelBuilder.Entity().Property("Version").HasConversion(); + modelBuilder.Entity().Property("Version").HasConversion(); + modelBuilder.Entity().Property("Version").HasConversion(); + modelBuilder.Entity().Property("Version").HasConversion(); + modelBuilder.Entity() + .OwnsOne( + s => s.Details, eb => + { + eb.Property("Version").IsRowVersion().HasConversion(); + }); + } } protected override void Seed(F1Context context) diff --git a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs index b41cf1feec7..eb1c901facf 100644 --- a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs +++ b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs @@ -16,8 +16,8 @@ // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore { - public abstract class OptimisticConcurrencyTestBase : IClassFixture - where TFixture : F1FixtureBase, new() + public abstract class OptimisticConcurrencyTestBase : IClassFixture + where TFixture : F1FixtureBase, new() { protected OptimisticConcurrencyTestBase(TFixture fixture) { diff --git a/test/EFCore.Specification.Tests/SerializationTestBase.cs b/test/EFCore.Specification.Tests/SerializationTestBase.cs index d9e99608e3c..91f3891c4d3 100644 --- a/test/EFCore.Specification.Tests/SerializationTestBase.cs +++ b/test/EFCore.Specification.Tests/SerializationTestBase.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore { public abstract class SerializationTestBase : IClassFixture - where TFixture : F1FixtureBase, new() + where TFixture : F1FixtureBase, new() { protected SerializationTestBase(TFixture fixture) => Fixture = fixture; diff --git a/test/EFCore.SqlServer.FunctionalTests/F1SqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/F1SqlServerFixture.cs index d3727505722..8422882f76b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/F1SqlServerFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/F1SqlServerFixture.cs @@ -6,7 +6,15 @@ namespace Microsoft.EntityFrameworkCore { - public class F1SqlServerFixture : F1RelationalFixture + public class F1ULongSqlServerFixture : F1SqlServerFixtureBase + { + } + + public class F1SqlServerFixture : F1SqlServerFixtureBase + { + } + + public abstract class F1SqlServerFixtureBase : F1RelationalFixture { protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance; @@ -18,27 +26,11 @@ protected override void BuildModelExternal(ModelBuilder modelBuilder) { base.BuildModelExternal(modelBuilder); - modelBuilder.Entity().Property("Version").IsRowVersion(); - modelBuilder.Entity().Property("Version").IsRowVersion(); - - modelBuilder.Entity().Property("Version") - .ValueGeneratedOnAddOrUpdate() - .IsConcurrencyToken(); - - modelBuilder.Entity( - eb => - { - eb.Property("Version").IsRowVersion().HasColumnName("Version"); - eb.Property(Sponsor.ClientTokenPropertyName).HasColumnName(Sponsor.ClientTokenPropertyName); - }); modelBuilder.Entity() .OwnsOne( s => s.Details, eb => { eb.Property(d => d.Space).HasColumnType("decimal(18,2)"); - eb.Property("Version").IsRowVersion().HasColumnName("Version"); - eb.Property(Sponsor.ClientTokenPropertyName).IsConcurrencyToken() - .HasColumnName(Sponsor.ClientTokenPropertyName); }); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs index 4b23d0ead52..1ceb209be47 100644 --- a/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs @@ -11,12 +11,30 @@ // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore { - public class OptimisticConcurrencySqlServerTest : OptimisticConcurrencyTestBase + public class OptimisticConcurrencyULongSqlServerTest : OptimisticConcurrencySqlServerTestBase + { + public OptimisticConcurrencyULongSqlServerTest(F1ULongSqlServerFixture fixture) + : base(fixture) + { + } + } + + public class OptimisticConcurrencySqlServerTest : OptimisticConcurrencySqlServerTestBase { public OptimisticConcurrencySqlServerTest(F1SqlServerFixture fixture) : base(fixture) { } + } + + public abstract class OptimisticConcurrencySqlServerTestBase + : OptimisticConcurrencyTestBase + where TFixture : F1FixtureBase, new() + { + protected OptimisticConcurrencySqlServerTestBase(TFixture fixture) + : base(fixture) + { + } [ConditionalFact] public async Task Modifying_concurrency_token_only_is_noop() @@ -28,22 +46,22 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( using var transaction = context.Database.BeginTransaction(); var driver = context.Drivers.Single(d => d.CarNumber == 1); driver.Podiums = StorePodiums; - var firstVersion = context.Entry(driver).Property("Version").CurrentValue; + var firstVersion = context.Entry(driver).Property("Version").CurrentValue; await context.SaveChangesAsync(); using var innerContext = CreateF1Context(); innerContext.Database.UseTransaction(transaction.GetDbTransaction()); driver = innerContext.Drivers.Single(d => d.CarNumber == 1); - Assert.NotEqual(firstVersion, innerContext.Entry(driver).Property("Version").CurrentValue); + Assert.NotEqual(firstVersion, innerContext.Entry(driver).Property("Version").CurrentValue); Assert.Equal(StorePodiums, driver.Podiums); - var secondVersion = innerContext.Entry(driver).Property("Version").CurrentValue; - innerContext.Entry(driver).Property("Version").CurrentValue = firstVersion; + var secondVersion = innerContext.Entry(driver).Property("Version").CurrentValue; + innerContext.Entry(driver).Property("Version").CurrentValue = firstVersion; await innerContext.SaveChangesAsync(); using var validationContext = CreateF1Context(); validationContext.Database.UseTransaction(transaction.GetDbTransaction()); driver = validationContext.Drivers.Single(d => d.CarNumber == 1); - Assert.Equal(secondVersion, validationContext.Entry(driver).Property("Version").CurrentValue); + Assert.Equal(secondVersion, validationContext.Entry(driver).Property("Version").CurrentValue); Assert.Equal(StorePodiums, driver.Podiums); }); } @@ -59,8 +77,8 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( var sponsor = context.Set().Single(); var sponsorEntry = c.Entry(sponsor); var detailsEntry = sponsorEntry.Reference(s => s.Details).TargetEntry; - var sponsorVersion = sponsorEntry.Property("Version").CurrentValue; - var detailsVersion = detailsEntry.Property("Version").CurrentValue; + var sponsorVersion = sponsorEntry.Property("Version").CurrentValue; + var detailsVersion = detailsEntry.Property("Version").CurrentValue; Assert.Null(sponsorEntry.Property(Sponsor.ClientTokenPropertyName).CurrentValue); sponsorEntry.Property(Sponsor.ClientTokenPropertyName).CurrentValue = 1; @@ -71,8 +89,8 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( await context.SaveChangesAsync(); - var newSponsorVersion = sponsorEntry.Property("Version").CurrentValue; - var newDetailsVersion = detailsEntry.Property("Version").CurrentValue; + var newSponsorVersion = sponsorEntry.Property("Version").CurrentValue; + var newDetailsVersion = detailsEntry.Property("Version").CurrentValue; Assert.Equal(newSponsorVersion, newDetailsVersion); Assert.NotEqual(sponsorVersion, newSponsorVersion); @@ -92,7 +110,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( using var transaction = context.Database.BeginTransaction(); var sponsor = context.Set().Single(); var sponsorEntry = c.Entry(sponsor); - var sponsorVersion = sponsorEntry.Property("Version").CurrentValue; + var sponsorVersion = sponsorEntry.Property("Version").CurrentValue; Assert.Null(sponsorEntry.Property(Sponsor.ClientTokenPropertyName).CurrentValue); sponsorEntry.Property(Sponsor.ClientTokenPropertyName).CurrentValue = 1; @@ -106,8 +124,8 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( await context.SaveChangesAsync(); - var newSponsorVersion = sponsorEntry.Property("Version").CurrentValue; - var newDetailsVersion = detailsEntry.Property("Version").CurrentValue; + var newSponsorVersion = sponsorEntry.Property("Version").CurrentValue; + var newDetailsVersion = detailsEntry.Property("Version").CurrentValue; Assert.Equal(newSponsorVersion, newDetailsVersion); Assert.NotEqual(sponsorVersion, newSponsorVersion); diff --git a/test/EFCore.Sqlite.FunctionalTests/F1SqliteFixture.cs b/test/EFCore.Sqlite.FunctionalTests/F1SqliteFixture.cs index 8a35cd4b2d2..71f266918ce 100644 --- a/test/EFCore.Sqlite.FunctionalTests/F1SqliteFixture.cs +++ b/test/EFCore.Sqlite.FunctionalTests/F1SqliteFixture.cs @@ -5,7 +5,15 @@ namespace Microsoft.EntityFrameworkCore { - public class F1SqliteFixture : F1RelationalFixture + public class F1ULongSqliteFixture : F1SqliteFixtureBase + { + } + + public class F1SqliteFixture : F1SqliteFixtureBase + { + } + + public abstract class F1SqliteFixtureBase : F1RelationalFixture { protected override ITestStoreFactory TestStoreFactory => PrivateCacheSqliteTestStoreFactory.Instance; diff --git a/test/EFCore.Sqlite.FunctionalTests/OptimisticConcurrencySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/OptimisticConcurrencySqliteTest.cs index e2cf6b944c2..f7aef6f9360 100644 --- a/test/EFCore.Sqlite.FunctionalTests/OptimisticConcurrencySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/OptimisticConcurrencySqliteTest.cs @@ -4,50 +4,78 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; +using Xunit; namespace Microsoft.EntityFrameworkCore { - public class OptimisticConcurrencySqliteTest : OptimisticConcurrencyTestBase + public class OptimisticConcurrencyULongSqliteTest : OptimisticConcurrencySqliteTestBase + { + public OptimisticConcurrencyULongSqliteTest(F1ULongSqliteFixture fixture) + : base(fixture) + { + } + } + + public class OptimisticConcurrencySqliteTest : OptimisticConcurrencySqliteTestBase { public OptimisticConcurrencySqliteTest(F1SqliteFixture fixture) : base(fixture) { } + } + + public abstract class OptimisticConcurrencySqliteTestBase + : OptimisticConcurrencyTestBase + where TFixture : F1FixtureBase, new() + { + protected OptimisticConcurrencySqliteTestBase(TFixture fixture) + : base(fixture) + { + } - // Override failing tests because SQLite does not allow store-generated row versions. - // Row version behavior could be imitated on SQLite. See Issue #2195 + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Simple_concurrency_exception_can_be_resolved_with_store_values() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Simple_concurrency_exception_can_be_resolved_with_client_values() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Simple_concurrency_exception_can_be_resolved_with_new_values() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Simple_concurrency_exception_can_be_resolved_with_store_values_using_equivalent_of_accept_changes() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Simple_concurrency_exception_can_be_resolved_with_store_values_using_Reload() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Updating_then_deleting_the_same_entity_results_in_DbUpdateConcurrencyException() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Updating_then_deleting_the_same_entity_results_in_DbUpdateConcurrencyException_which_can_be_resolved_with_store_values() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Change_in_independent_association_after_change_in_different_concurrency_token_results_in_independent_association_exception() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Change_in_independent_association_results_in_independent_association_exception() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Two_concurrency_issues_in_one_to_many_related_entities_can_be_handled_by_dealing_with_dependent_first() => Task.FromResult(true); + [ConditionalFact(Skip = "Optimistic Offline Lock #2195")] public override Task Two_concurrency_issues_in_one_to_one_related_entities_can_be_handled_by_dealing_with_dependent_first() => Task.FromResult(true);