public async Task UpdateAsync_ShouldReturnCollectionWithOnlyIncludedPropertiesUpdated_WhenEntitiesMatchAndIncludedPropertyExpresionsArePassed(DbProvider provider, TestConfiguration testConfiguration = TestConfiguration.Default) { TestEntityCompositeKey[] existingEntities = new[] { new TestEntityCompositeKey { IdPartA = "Should not be updated 1", IdPartB = "B", IntTestValue = 561645, BoolTestValue = false, DateTimeTestValue = DateTime.UtcNow, LongTestValue = 54123 }, new TestEntityCompositeKey { IdPartA = "Should not be updated 2", IdPartB = "B", IntTestValue = 56123, BoolTestValue = true, DateTimeTestValue = DateTime.UtcNow, LongTestValue = 1231 }, new TestEntityCompositeKey { IdPartA = "Should be updated 3", IdPartB = "B", IntTestValue = 111, BoolTestValue = true, DateTimeTestValue = DateTime.UtcNow, LongTestValue = 65465132165 }, }; TestEntityCompositeKey[] expectedEntities = new[] { new TestEntityCompositeKey { IdPartA = "Should not be updated 1", IdPartB = "B", IntTestValue = -1, BoolTestValue = true, DateTimeTestValue = DateTime.UtcNow.AddDays(1), LongTestValue = 781 }, new TestEntityCompositeKey { IdPartA = "Should be updated 3", IdPartB = "B", IntTestValue = 561235164, BoolTestValue = false, DateTimeTestValue = DateTime.UtcNow.AddDays(1), LongTestValue = 165465132165 }, }; using TestDbContext context = await ContextFactory.GetDbContextAsync(provider, seedData : existingEntities, testConfiguration : testConfiguration); // Include long and datetime values - they are the only items expected to be updated based on the mocked data. InclusionBuilder <TestEntityCompositeKey> inclusionBuilder = new InclusionBuilder <TestEntityCompositeKey>() .Include(x => x.LongTestValue) .Include(nameof(TestEntityCompositeKey.DateTimeTestValue)); // Invoke the method and check that the result the updated expected entities IReadOnlyCollection <TestEntityCompositeKey> result = await context.UpdateAsync( expectedEntities, condition : x => x.Incoming.IntTestValue > x.Current.IntTestValue, // Only update if IntTestValue is greater than the incoming value, which rules out "Should not be updated 1" clusivityBuilder : inclusionBuilder); var expectedUpdatedEntity = new TestEntityCompositeKey { IdPartA = expectedEntities[1].IdPartA, IdPartB = expectedEntities[1].IdPartB, IntTestValue = existingEntities[2].IntTestValue, // We did not include this field in the update => it should have its original value BoolTestValue = existingEntities[2].BoolTestValue, // We did not include this field in the update => it should have its original value DateTimeTestValue = expectedEntities[1].DateTimeTestValue, LongTestValue = expectedEntities[1].LongTestValue, }; result.Should().BeEquivalentTo(new[] { expectedUpdatedEntity }); // Validate that the DB is updated context.TestEntitiesWithCompositeKey.Should().BeEquivalentTo(new[] { existingEntities[0], existingEntities[1], expectedUpdatedEntity }); }
public async Task UpdateAsync_ShouldReturnAffectedUpdatedCollection_WhenASubsetOfEntitiesAreMatchingWithConditionUsingTvpInterceptor() { TestInterceptorEntity[] existingEntities = Enumerable.Range(0, 52).Select(id => new TestInterceptorEntity { Id = id.ToString(CultureInfo.InvariantCulture), IntTestValue = id % 2, BoolTestValue = false, StringTestValue = "short string", }).ToArray(); TestInterceptorEntity[] expectedEntities = Enumerable.Range(0, 52).Select(id => new TestInterceptorEntity { Id = id.ToString(CultureInfo.InvariantCulture), IntTestValue = 1, BoolTestValue = true, // The string field has a max length of 25 chars set with an attribute. // We're extending the max length with the TvpInterceptor by changing the type it will have in the temporary table. StringTestValue = "a really long string which is longer than the limit we have on the property", }).ToArray(); var interceptedProperties = new List <IInterceptedProperty>(); TestTableValuedParameterInterceptor.TestCallback = (properties) => interceptedProperties.AddRange(properties); // We're only using Table Valued Parameters in SqlServer using TestDbContext context = await ContextFactory.GetDbContextAsync(DbProvider.SqlServer, seedData : existingEntities); // Make sure we're using TVP and add the test interceptor context.ManipulationExtensionsConfiguration.SqlServerConfiguration.AddEntityConifugration <TestInterceptorEntity>( new Configuration.EntityConifugration { UseTableValuedParametersParameterCountTreshold = 0, TableValuedParameterInterceptor = new TestTableValuedParameterInterceptor(), }); // Include bool values - they are the only items expected to be updated based on the mocked data. InclusionBuilder <TestInterceptorEntity> inclusionBuilder = new InclusionBuilder <TestInterceptorEntity>().Include(x => x.BoolTestValue); // Invoke the method and check that the result the updated expected entities IReadOnlyCollection <TestInterceptorEntity> result = await context.UpdateAsync( expectedEntities, condition : x => x.Incoming.IntTestValue == x.Current.IntTestValue, // Only update if IntTestValue is equal to the incoming value clusivityBuilder : inclusionBuilder); Assert.AreEqual(expectedEntities.Length / 2, result.Count); Assert.IsTrue(result.All(r => r.BoolTestValue)); // Validate that the DB is updated context.TestInterceptorEntities.Should().BeEquivalentTo(existingEntities.Select(e => new TestInterceptorEntity { Id = e.Id, IntTestValue = e.IntTestValue, BoolTestValue = e.IntTestValue == 1, StringTestValue = e.StringTestValue, })); // Validate the TvpInterceptor has been called and what it returned foreach (KeyValuePair <string, string> propertyKvp in TestTableValuedParameterInterceptor.PropertyTypeOverrides) { Assert.AreEqual(1, interceptedProperties.Count(p => p.ColumnName == propertyKvp.Key && p.ColumnType == propertyKvp.Value)); } Assert.AreEqual(typeof(TestInterceptorEntity).GetProperties().Length, interceptedProperties.Count); }