diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/Benday.EfCore.SqlServer.IntegrationTests.csproj b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/Benday.EfCore.SqlServer.IntegrationTests.csproj index df150d8..22cc17c 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/Benday.EfCore.SqlServer.IntegrationTests.csproj +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/Benday.EfCore.SqlServer.IntegrationTests.csproj @@ -1,18 +1,18 @@ - + - netcoreapp3.1 + net6.0 false - - - - - + + + + + - + diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/DirectlyAgainstDbContextFixture.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/DirectlyAgainstDbContextFixture.cs index 35b2bab..fa16987 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/DirectlyAgainstDbContextFixture.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/DirectlyAgainstDbContextFixture.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Collections.Generic; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Console; using System.Linq.Expressions; using Microsoft.Extensions.DependencyInjection; @@ -14,73 +13,66 @@ namespace Benday.EfCore.SqlServer.IntegrationTests [TestClass] public class DirectlyAgainstDbContextFixture { - private readonly string _ConnectionString = "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;"; - + private readonly string _connectionString = "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;"; + [TestMethod] public void CreateSampleData() { // arrange - + // act var data = CreateSamplePersonRecords(); - + // assert - + Assert.AreNotEqual(0, data.Count, "There should be test data records"); - - using (var context = GetDbContext()) - { - var reloaded = context.Persons.ToList(); - - Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + var reloaded = context.Persons.ToList(); + Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void CreateSampleData_CleansUpOldData() { // arrange - + // act CreateSamplePersonRecords(); - + var data = CreateSamplePersonRecords(); - + // assert - + Assert.AreNotEqual(0, data.Count, "There should be test data records"); - - using (var context = GetDbContext()) - { - var reloaded = context.Persons.ToList(); - - Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + var reloaded = context.Persons.ToList(); + + Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void LinqQuery_ContainsOrQueryAgainstDbContext_TwoCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "bonk"; var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var query = context.Persons.Where( - p => p.FirstName.Contains(searchString) || p.LastName.Contains(searchString)); - - DebugIQueryable(query); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var query = context.Persons.Where( + p => p.FirstName.Contains(searchString) || p.LastName.Contains(searchString)); + + DebugIQueryable(query); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void LinqQuery_ContainsAndQueryAgainstDbContext_ReturnsOneMatches() { @@ -89,41 +81,37 @@ public void LinqQuery_ContainsAndQueryAgainstDbContext_ReturnsOneMatches() var searchStringFirstName = "all"; var searchStringLastName = "onk"; var expectedCount = 1; - - using (var context = GetDbContext()) - { - // act - var actual = context.Persons.Where( - p => p.FirstName.Contains(searchStringFirstName) && - p.LastName.Contains(searchStringLastName)).ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var actual = context.Persons.Where( + p => p.FirstName.Contains(searchStringFirstName) && + p.LastName.Contains(searchStringLastName)).ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void LinqQuery_ContainsAndQueryAgainstDbContext_OneCriteria() { // arrange var data = CreateSamplePersonRecords(); var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var query = context.Persons.Where( - p => p.LastName.Contains("onk")); - - DebugIQueryable(query); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var query = context.Persons.Where( + p => p.LastName.Contains("onk")); + + DebugIQueryable(query); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void LinqQuery_ContainsAndQueryAgainstDbContext_StartsWith_OneCriteria_OneResult() { @@ -131,20 +119,18 @@ public void LinqQuery_ContainsAndQueryAgainstDbContext_StartsWith_OneCriteria_On var data = CreateSamplePersonRecords(); var searchStringLastName = "had"; var expectedCount = 1; - - using (var context = GetDbContext()) - { - // act - var query = context.Persons.Where( - p => p.LastName.StartsWith(searchStringLastName)); - - DebugIQueryable(query); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var query = context.Persons.Where( + p => p.LastName.StartsWith(searchStringLastName)); + + DebugIQueryable(query); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } [TestMethod] @@ -155,130 +141,118 @@ public void DynamicQuery_ContainsAndQueryAgainstDbContext_ReturnsOneMatches() var searchStringFirstName = "all"; var searchStringLastName = "onk"; var expectedCount = 1; - - using (var context = GetDbContext()) - { - // act - var query = context.Persons.AsQueryable(); - - query = query.Where(p => p.FirstName.Contains(searchStringFirstName)); - query = query.Where(p => p.LastName.Contains(searchStringLastName)); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var query = context.Persons.AsQueryable(); + + query = query.Where(p => p.FirstName.Contains(searchStringFirstName)); + query = query.Where(p => p.LastName.Contains(searchStringLastName)); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void DynamicQuery_Equals_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 1; - - using (var context = GetDbContext()) - { - // act - var expression = GetSingleEquals("LastName", "Bonkbonk"); - - var query = context.Persons.Where(expression); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var expression = GetSingleEquals("LastName", "Bonkbonk"); + + var query = context.Persons.Where(expression); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void DynamicQuery_Contains_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var expression = GetContains("LastName", "onk"); - - var query = context.Persons.Where(expression); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var expression = GetContains("LastName", "onk"); + + var query = context.Persons.Where(expression); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void DynamicQuery_NoCriteria_WithOrderBy() { // arrange var data = CreateSamplePersonRecords(); var expectedCount = 6; - - using (var context = GetDbContext()) - { - // act - - var query = context.Persons.OrderBy(p => p.LastName).OrderBy(p => p.FirstName); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + + var query = context.Persons.OrderBy(p => p.LastName).OrderBy(p => p.FirstName); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void DynamicQuery_Contains_TwoCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var expression = GetContains("LastName", "FirstName", "onk"); - - var query = context.Persons.Where(expression); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var expression = GetContains("LastName", "FirstName", "onk"); + + var query = context.Persons.Where(expression); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void DynamicQuery_Contains_WithChildCriteria() { // arrange var data = CreateSamplePersonRecords(); var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var personExpressions = GetContains("LastName", "FirstName", "onk"); - - Expression> childExpression = p => p.Notes.Any(n => n.NoteText.Contains("onk")); - - var queryExpression = personExpressions.Or(childExpression); - - var query = context.Persons.Where(queryExpression); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var personExpressions = GetContains("LastName", "FirstName", "onk"); + + Expression> childExpression = p => p.Notes.Any(n => n.NoteText.Contains("onk")); + + var queryExpression = personExpressions.Or(childExpression); + + var query = context.Persons.Where(queryExpression); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void DynamicQuery_Contains_TwoCriteria_AlternateVersion_EvaluatedInMemory_ThrowsException() @@ -286,108 +260,107 @@ public void DynamicQuery_Contains_TwoCriteria_AlternateVersion_EvaluatedInMemory // arrange var data = CreateSamplePersonRecords(); var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - /* + + using var context = GetDbContext(); + // act + /* Expression> expr0 = p => p.FirstName.Contains("onk"); - Expression> expr1 = p => p.LastName.Contains("onk"); - */ - - Predicate expr0 = p => p.FirstName.Contains("onk"); - Predicate expr1 = p => p.LastName.Contains("onk"); - - var orExpressions = new List>(); - - orExpressions.Add(expr0); - orExpressions.Add(expr1); - - Expression> exprWhere = - p => orExpressions.Any(expr => expr(p)); - - var query = context.Persons.Where(exprWhere); - - var actual = query.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + Expression> expr1 = p => p.LastName.Contains("onk"); + */ + + Predicate expr0 = p => p.FirstName.Contains("onk"); + Predicate expr1 = p => p.LastName.Contains("onk"); + + var orExpressions = new List> + { + expr0, + expr1 + }; + + Expression> exprWhere = + p => orExpressions.Any(expr => expr(p)); + + var query = context.Persons.Where(exprWhere); + + var actual = query.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - - - public Expression> GetSingleEquals(string propertyName, string searchValue) + + + public static Expression> GetSingleEquals(string propertyName, string searchValue) { var parameterItem = Expression.Parameter(typeof(T), "item"); - + var lambda = Expression.Lambda>( Expression.Equal( - Expression.Property( - parameterItem, - propertyName - ), - Expression.Constant(searchValue) + Expression.Property( + parameterItem, + propertyName + ), + Expression.Constant(searchValue) ), parameterItem - ); - + ); + // var result = queryableData.Where(lambda); return lambda; } - - public Expression> GetContains(string propertyName, string searchValue) + + public static Expression> GetContains(string propertyName, string searchValue) { var parameterItem = Expression.Parameter(typeof(T), "item"); - + var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); - + var lambda = Expression.Lambda>( Expression.Call( - Expression.Property( - parameterItem, - propertyName - ), - containsMethod, - Expression.Constant(searchValue)), - parameterItem + Expression.Property( + parameterItem, + propertyName + ), + containsMethod, + Expression.Constant(searchValue)), + parameterItem ); - + return lambda; } - - public Expression> GetContains(string propertyName1, string propertyName2, string searchValue) + + public static Expression> GetContains(string propertyName1, string propertyName2, string searchValue) { var parameterItem = Expression.Parameter(typeof(T), "item"); - + var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); - + var left = Expression.Lambda>( Expression.Call( - Expression.Property( - parameterItem, - propertyName1 - ), - containsMethod, - Expression.Constant(searchValue)), - parameterItem + Expression.Property( + parameterItem, + propertyName1 + ), + containsMethod, + Expression.Constant(searchValue)), + parameterItem ); - + var right = Expression.Lambda>( Expression.Call( - Expression.Property( - parameterItem, - propertyName2 - ), - containsMethod, - Expression.Constant(searchValue)), - parameterItem + Expression.Property( + parameterItem, + propertyName2 + ), + containsMethod, + Expression.Constant(searchValue)), + parameterItem ); - + var lambda = left.Or(right); - + return lambda; } - + [TestMethod] public void CreateContainsOrQueryAgainstDbContext_WriteExpressionsToConsole() { @@ -395,111 +368,107 @@ public void CreateContainsOrQueryAgainstDbContext_WriteExpressionsToConsole() var data = CreateSamplePersonRecords(); var searchString = "bonk"; var expectedCount = 2; - - using (var context = GetDbContext()) - { - // act - var actualIQueryable = context.Persons.Where( - p => p.FirstName.Contains(searchString) || p.LastName.Contains(searchString)); - - DebugIQueryable(actualIQueryable); - - var actual = actualIQueryable.ToList(); - - // assert - Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + // act + var actualIQueryable = context.Persons.Where( + p => p.FirstName.Contains(searchString) || p.LastName.Contains(searchString)); + + DebugIQueryable(actualIQueryable); + + var actual = actualIQueryable.ToList(); + + // assert + Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - - private void DebugIQueryable(IQueryable actualIQueryable) + + private static void DebugIQueryable(IQueryable actualIQueryable) { - var rootExpression = actualIQueryable.Expression; - - Console.WriteLine("asdf"); + Console.WriteLine(actualIQueryable); } - + private List CreateSamplePersonRecords() { - using (var context = GetDbContext()) - { - DeleteExistingPersonRecords(context); - - return CreateSamplePersonRecords(context); - } + using var context = GetDbContext(); + DeleteExistingPersonRecords(context); + + return CreateSamplePersonRecords(context); } - - private List CreateSamplePersonRecords(TestDbContext context) + + private static List CreateSamplePersonRecords(TestDbContext context) { - var returnValues = new List(); - - returnValues.Add(CreatePerson("James", "Ratt")); - returnValues.Add(CreatePerson("Mary", "Haddalitalamb")); - returnValues.Add(CreatePerson("Bing", "Bonkbonk")); - returnValues.Add(CreatePerson("Sally", "Kahbonka")); - returnValues.Add(CreatePerson("Turk", "Menistan")); - returnValues.Add(CreatePerson("Mary Ann", "Thump")); - + var returnValues = new List + { + CreatePerson("James", "Ratt"), + CreatePerson("Mary", "Haddalitalamb"), + CreatePerson("Bing", "Bonkbonk"), + CreatePerson("Sally", "Kahbonka"), + CreatePerson("Turk", "Menistan"), + CreatePerson("Mary Ann", "Thump") + }; + context.Persons.AddRange(returnValues); - + context.SaveChanges(); - + return returnValues; } - - private Person CreatePerson(string firstName, string lastName) + + private static Person CreatePerson(string firstName, string lastName) { - var temp = new Person(); - - temp.FirstName = firstName; - temp.LastName = lastName; - - var noteText0 = - String.Format("{0} {1} note {2}", firstName, lastName, "0"); - + var temp = new Person + { + FirstName = firstName, + LastName = lastName + }; + + var noteText0 = + string.Format("{0} {1} note {2}", firstName, lastName, "0"); + var noteText1 = - String.Format("{0} {1} note {2}", firstName, lastName, "1"); - + string.Format("{0} {1} note {2}", firstName, lastName, "1"); + var noteText2 = - String.Format("{0} {1} note {2}", firstName, lastName, "2"); - + string.Format("{0} {1} note {2}", firstName, lastName, "2"); + temp.Notes.Add(new PersonNote() { NoteText = noteText0 }); temp.Notes.Add(new PersonNote() { NoteText = noteText1 }); temp.Notes.Add(new PersonNote() { NoteText = noteText2 }); - + return temp; } - - private void DeleteExistingPersonRecords(TestDbContext context) + + private static void DeleteExistingPersonRecords(TestDbContext context) { var existing = context.Persons.ToList(); - + existing.ForEach(p => context.Persons.Remove(p)); - + context.SaveChanges(); } - - private ILoggerFactory GetLoggerFactory() + + private static ILoggerFactory GetLoggerFactory() { IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(builder => - builder.AddConsole() - .AddFilter(DbLoggerCategory.Database.Command.Name, - LogLevel.Information)); + builder.AddConsole() + .AddFilter(DbLoggerCategory.Database.Command.Name, + LogLevel.Information)); return serviceCollection.BuildServiceProvider() - .GetService(); + .GetService(); } - + private TestDbContext GetDbContext() { var optionsBuilder = new DbContextOptionsBuilder(); - + optionsBuilder.UseLoggerFactory(GetLoggerFactory()); optionsBuilder.EnableSensitiveDataLogging(true); - optionsBuilder.UseSqlServer(_ConnectionString); - - TestDbContext context = new TestDbContext(optionsBuilder.Options); - + optionsBuilder.UseSqlServer(_connectionString); + + var context = new TestDbContext(optionsBuilder.Options); + return context; } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/EfCoreUnitTestSetup.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/EfCoreUnitTestSetup.cs new file mode 100644 index 0000000..149bb62 --- /dev/null +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/EfCoreUnitTestSetup.cs @@ -0,0 +1,47 @@ +using Benday.EfCore.SqlServer.TestApi; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Benday.EfCore.SqlServer.IntegrationTests +{ + [TestClass] + public static class EfCoreUnitTestSetup + { + private static readonly string _ConnectionString = "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;"; + + [AssemblyInitializeAttribute] + #pragma warning disable IDE0060 // Remove unused parameter + public static void OnAssemblyInitialize(TestContext testContext) + #pragma warning restore IDE0060 // Remove unused parameter + { + using var dbcontext = GetDbContext(); + dbcontext.Database.EnsureCreated(); + } + + private static ILoggerFactory GetLoggerFactory() + { + IServiceCollection serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => + builder.AddConsole() + .AddFilter(DbLoggerCategory.Database.Command.Name, + LogLevel.Information)); + return serviceCollection.BuildServiceProvider() + .GetService(); + } + + private static TestDbContext GetDbContext() + { + var optionsBuilder = new DbContextOptionsBuilder(); + + optionsBuilder.UseLoggerFactory(GetLoggerFactory()); + optionsBuilder.EnableSensitiveDataLogging(true); + optionsBuilder.UseSqlServer(_ConnectionString); + + var context = new TestDbContext(optionsBuilder.Options); + + return context; + } + } +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/PersonSearchableRepositoryFixture.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/PersonSearchableRepositoryFixture.cs index da24f14..d2a2378 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/PersonSearchableRepositoryFixture.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.IntegrationTests/PersonSearchableRepositoryFixture.cs @@ -1,12 +1,9 @@ -using System; using Benday.EfCore.SqlServer.TestApi; using Microsoft.EntityFrameworkCore; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; using System.Collections.Generic; using Microsoft.Extensions.Logging; -// using Microsoft.Extensions.Logging.Console; -using System.Linq.Expressions; using Microsoft.Extensions.DependencyInjection; using Benday.Common; @@ -15,571 +12,567 @@ namespace Benday.EfCore.SqlServer.IntegrationTests [TestClass] public class PersonSearchableRepositoryFixture { - private readonly string _ConnectionString = "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;"; - + private const string _ConnectionString = "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;"; + [TestInitialize] public void OnTestInitialize() { - _SystemUnderTest = null; + _systemUnderTest = null; } - - private SqlPersonRepository _SystemUnderTest; + + private SqlPersonRepository _systemUnderTest; public SqlPersonRepository SystemUnderTest { get { - if (_SystemUnderTest == null) + if (_systemUnderTest == null) { - _SystemUnderTest = new SqlPersonRepository(GetDbContext()); + _systemUnderTest = new SqlPersonRepository(GetDbContext()); } - - return _SystemUnderTest; + + return _systemUnderTest; } } - + [TestMethod] public void CreateSampleData() { // arrange - + // act var data = CreateSamplePersonRecords(); - + // assert - + Assert.AreNotEqual(0, data.Count, "There should be test data records"); - - using (var context = GetDbContext()) - { - var reloaded = context.Persons.ToList(); - - Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + var reloaded = context.Persons.ToList(); + + Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void CreateSampleData_CleansUpOldData() { // arrange - + // act CreateSamplePersonRecords(); - + var data = CreateSamplePersonRecords(); - + // assert - + Assert.AreNotEqual(0, data.Count, "There should be test data records"); - - using (var context = GetDbContext()) - { - var reloaded = context.Persons.ToList(); - - Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); - } + + using var context = GetDbContext(); + var reloaded = context.Persons.ToList(); + + Assert.AreEqual(data.Count, reloaded.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Contains_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "onk"; var expectedCount = 2; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Contains, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Contains_TwoCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "onk"; var expectedCount = 3; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Contains, searchString, SearchOperator.Or); search.AddArgument("FirstName", SearchMethod.Contains, searchString, SearchOperator.Or); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Contains_TwoCriteria_NoResults() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "asdfqwer"; var expectedCount = 0; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Contains, searchString); search.AddArgument("FirstName", SearchMethod.Contains, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Contains_ChildEntitySearch() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "dal"; var expectedCount = 1; - + var search = new Search(); search.AddArgument("NoteText", SearchMethod.Contains, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Equals_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "thump"; var expectedCount = 2; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Equals, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_Equals_TwoCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "onk"; var expectedCount = 3; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Contains, searchString, SearchOperator.Or); search.AddArgument("FirstName", SearchMethod.Contains, searchString, SearchOperator.Or); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_StartsWith_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "had"; var expectedCount = 1; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.StartsWith, searchString, SearchOperator.Or); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_StartsWith_TwoCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 1; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.StartsWith, "thu", SearchOperator.And); search.AddArgument("FirstName", SearchMethod.StartsWith, "glad", SearchOperator.And); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_NotEqual_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "thump"; var expectedCount = 6; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.IsNotEqual, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_AddsIncludesForChildObjects() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "thump"; var expectedCount = 6; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.IsNotEqual, searchString); - + // act var result = SystemUnderTest.Search(search); var actuals = result.Results; - + // assert Assert.AreEqual(expectedCount, actuals.Count, "Reloaded record count was wrong"); - + foreach (var actual in actuals) { Assert.IsNotNull(actual.Notes, "Notes collection was null."); - + Assert.AreNotEqual(0, actual.Notes.Count, "Note count should not be zero."); } } - + [TestMethod] public void PersonSearchableRepository_Search_EndsWith_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "lamb"; var expectedCount = 1; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.EndsWith, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - + [TestMethod] public void PersonSearchableRepository_Search_NoCriteria_OneSort_Ascending() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 8; - + var search = new Search(); search.AddSort("LastName"); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - + var expected = actual.OrderBy(x => x.LastName).ToList(); - + AssertAreEqual(expected, actual, "Sorted by last name ascending"); } - + [DataTestMethod] [DataRow(" ", DisplayName = "whitespace string")] [DataRow("", DisplayName = "empty string")] public void PersonSearchableRepository_Search_SingleSort_IgnoresEmptySort(string sortBy) { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 8; - + var search = new Search(); search.AddSort(sortBy); - + Assert.AreEqual(1, search.Sorts.Count, "Sort count was wrong"); - + // act var unsortedResults = SystemUnderTest.Search(new Search()).Results; var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - + var expected = unsortedResults.ToList(); - + AssertAreEqual(expected, actual, "Sorted by nothing in particular"); } - + [DataTestMethod] [DataRow(" ", DisplayName = "whitespace string")] [DataRow("", DisplayName = "empty string")] public void PersonSearchableRepository_Search_MultipleSorts_IgnoresEmptySort(string sortBy) { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 8; - + var search = new Search(); search.AddSort(nameof(Person.FirstName)); search.AddSort(sortBy); - + Assert.AreEqual(2, search.Sorts.Count, "Sort count was wrong"); - + var expectedDataSearch = new Search(); expectedDataSearch.AddSort(nameof(Person.FirstName)); - + // act var unsortedResults = SystemUnderTest.Search(expectedDataSearch).Results; var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - + var expected = unsortedResults.ToList(); - + AssertAreEqual(expected, actual, "Sorted by nothing in particular"); } - + [TestMethod] public void PersonSearchableRepository_Search_NoCriteria_TwoSorts_Ascending() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 8; - + var search = new Search(); search.AddSort("LastName"); search.AddSort("FirstName"); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - + var expected = actual.OrderBy(x => x.LastName).ThenBy(x => x.FirstName).ToList(); - + AssertAreEqual(expected, actual, "Sorted by last name ascending"); } - + [TestMethod] public void PersonSearchableRepository_Search_NoCriteria_TwoSorts_AscendingAndDescending() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 8; - + var search = new Search(); search.AddSort("LastName"); search.AddSort("FirstName", SearchConstants.SortDirectionDescending); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - + var expected = actual.OrderBy(x => x.LastName).ThenByDescending(x => x.FirstName).ToList(); - + AssertAreEqual(expected, actual, "Sorted by last name ascending"); } - + [TestMethod] public void PersonSearchableRepository_Search_OneCriteria_OneSort_Ascending() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 2; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Equals, "Thump"); search.AddSort("FirstName", SearchConstants.SortDirectionAscending); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - - + + Assert.AreEqual("Gladys", actual[0].FirstName, "Unexpected first name item 0"); Assert.AreEqual("Mary Ann", actual[1].FirstName, "Unexpected first name item 1"); } - + [TestMethod] public void PersonSearchableRepository_Search_OneCriteria_OneSort_Descending() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var expectedCount = 2; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.Equals, "Thump"); search.AddSort("FirstName", SearchConstants.SortDirectionDescending); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); - - + + Assert.AreEqual("Mary Ann", actual[0].FirstName, "Unexpected first name item 0"); Assert.AreEqual("Gladys", actual[1].FirstName, "Unexpected first name item 1"); } - - private void AssertAreEqual(List expected, IList actual, string message) + + private static void AssertAreEqual(List expected, IList actual, string message) { var actualAsList = actual.ToList(); - + CollectionAssert.AreEqual(expected, actualAsList, message); } - + [TestMethod] public void PersonSearchableRepository_Search_DoesNotContain_OneCriteria() { // arrange - var data = CreateSamplePersonRecords(); + CreateSamplePersonRecords(); var searchString = "bon"; var expectedCount = 6; - + var search = new Search(); search.AddArgument("LastName", SearchMethod.DoesNotContain, searchString); - + // act var result = SystemUnderTest.Search(search); var actual = result.Results; - + // assert Assert.AreEqual(expectedCount, actual.Count, "Reloaded record count was wrong"); } - - private List CreateSamplePersonRecords() + + private static List CreateSamplePersonRecords() { - using (var context = GetDbContext()) - { - DeleteExistingPersonRecords(context); - - return CreateSamplePersonRecords(context); - } + using var context = GetDbContext(); + DeleteExistingPersonRecords(context); + + return CreateSamplePersonRecords(context); } - - private List CreateSamplePersonRecords(TestDbContext context) + + private static List CreateSamplePersonRecords(TestDbContext context) { - var returnValues = new List(); - - returnValues.Add(CreatePerson("James", "Ratt")); - returnValues.Add(CreatePerson("Mary", "Haddalitalamb")); - returnValues.Add(CreatePerson("Bing", "Bonkbonk")); - returnValues.Add(CreatePerson("Sally", "Kahbonka")); - returnValues.Add(CreatePerson("Turk", "Menistan")); - returnValues.Add(CreatePerson("Mary Ann", "Thump")); - returnValues.Add(CreatePerson("Gladys", "Thump")); - returnValues.Add(CreatePerson("Bonk", "Errific")); - + var returnValues = new List + { + CreatePerson("James", "Ratt"), + CreatePerson("Mary", "Haddalitalamb"), + CreatePerson("Bing", "Bonkbonk"), + CreatePerson("Sally", "Kahbonka"), + CreatePerson("Turk", "Menistan"), + CreatePerson("Mary Ann", "Thump"), + CreatePerson("Gladys", "Thump"), + CreatePerson("Bonk", "Errific") + }; + context.Persons.AddRange(returnValues); - + context.SaveChanges(); - + return returnValues; } - - private Person CreatePerson(string firstName, string lastName) + + private static Person CreatePerson(string firstName, string lastName) { - var temp = new Person(); - - temp.FirstName = firstName; - temp.LastName = lastName; - + var temp = new Person + { + FirstName = firstName, + LastName = lastName + }; + var noteText0 = - String.Format("{0} {1} note {2}", firstName, lastName, "0"); - + string.Format("{0} {1} note {2}", firstName, lastName, "0"); + var noteText1 = - String.Format("{0} {1} note {2}", firstName, lastName, "1"); - + string.Format("{0} {1} note {2}", firstName, lastName, "1"); + var noteText2 = - String.Format("{0} {1} note {2}", firstName, lastName, "2"); - + string.Format("{0} {1} note {2}", firstName, lastName, "2"); + temp.Notes.Add(new PersonNote() { NoteText = noteText0 }); temp.Notes.Add(new PersonNote() { NoteText = noteText1 }); temp.Notes.Add(new PersonNote() { NoteText = noteText2 }); - + return temp; } - - private void DeleteExistingPersonRecords(TestDbContext context) + + private static void DeleteExistingPersonRecords(TestDbContext context) { var existing = context.Persons.ToList(); - + existing.ForEach(p => context.Persons.Remove(p)); - + context.SaveChanges(); } - - private ILoggerFactory GetLoggerFactory() + + private static ILoggerFactory GetLoggerFactory() { IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(builder => - builder.AddConsole() - .AddFilter(DbLoggerCategory.Database.Command.Name, - LogLevel.Information)); + builder.AddConsole() + .AddFilter(DbLoggerCategory.Database.Command.Name, + LogLevel.Information)); return serviceCollection.BuildServiceProvider() - .GetService(); + .GetService(); } - - private TestDbContext GetDbContext() + + private static TestDbContext GetDbContext() { var optionsBuilder = new DbContextOptionsBuilder(); - + optionsBuilder.UseLoggerFactory(GetLoggerFactory()); optionsBuilder.EnableSensitiveDataLogging(true); optionsBuilder.UseSqlServer(_ConnectionString); - - TestDbContext context = new TestDbContext(optionsBuilder.Options); - + + var context = new TestDbContext(optionsBuilder.Options); + return context; } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Benday.EfCore.SqlServer.TestApi.csproj b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Benday.EfCore.SqlServer.TestApi.csproj index 66bc98d..ad808c7 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Benday.EfCore.SqlServer.TestApi.csproj +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Benday.EfCore.SqlServer.TestApi.csproj @@ -1,23 +1,21 @@  - netcoreapp3.1 + net6.0 - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - + + + + + + - - - + + + + diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.Designer.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.Designer.cs index 921eec3..0d22e1f 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.Designer.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.Designer.cs @@ -1,4 +1,4 @@ -// +// using Benday.EfCore.SqlServer.TestApi; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -14,29 +14,29 @@ partial class InitialMigration { protected override void BuildTargetModel(ModelBuilder modelBuilder) { -#pragma warning disable 612, 618 - modelBuilder + #pragma warning disable 612, 618 + modelBuilder .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("FirstName") - .IsRequired(); - - b.Property("LastName") - .IsRequired(); - - b.HasKey("Id"); - - b.ToTable("Person"); - }); -#pragma warning restore 612, 618 + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FirstName") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + #pragma warning restore 612, 618 } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.cs index 07e0cec..b56a00e 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904130255_InitialMigration.cs @@ -12,14 +12,14 @@ protected override void Up(MigrationBuilder migrationBuilder) columns: table => new { Id = table.Column(nullable: false) - .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), FirstName = table.Column(nullable: false), LastName = table.Column(nullable: false) }, - constraints: table => - { - table.PrimaryKey("PK_Person", x => x.Id); - }); + constraints: table => + { + table.PrimaryKey("PK_Person", x => x.Id); + }); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.Designer.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.Designer.cs index d4f3c17..381869a 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.Designer.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.Designer.cs @@ -1,4 +1,4 @@ -// +// using Benday.EfCore.SqlServer.TestApi; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -14,55 +14,55 @@ partial class PersonNotes { protected override void BuildTargetModel(ModelBuilder modelBuilder) { -#pragma warning disable 612, 618 - modelBuilder + #pragma warning disable 612, 618 + modelBuilder .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("FirstName") - .IsRequired(); - - b.Property("LastName") - .IsRequired(); - - b.HasKey("Id"); - - b.ToTable("Person"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FirstName") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("NoteText") - .IsRequired(); - - b.Property("PersonId"); - - b.HasKey("Id"); - - b.HasIndex("PersonId"); - - b.ToTable("PersonNote"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("NoteText") + .IsRequired(); + + b.Property("PersonId"); + + b.HasKey("Id"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonNote"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") - .WithMany("Notes") - .HasForeignKey("PersonId") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 + { + b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") + .WithMany("Notes") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade); + }); + #pragma warning restore 612, 618 } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.cs index 407136b..0567c85 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190904190208_PersonNotes.cs @@ -12,20 +12,20 @@ protected override void Up(MigrationBuilder migrationBuilder) columns: table => new { Id = table.Column(nullable: false) - .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), PersonId = table.Column(nullable: false), NoteText = table.Column(nullable: false) }, - constraints: table => - { - table.PrimaryKey("PK_PersonNote", x => x.Id); - table.ForeignKey( - name: "FK_PersonNote_Person_PersonId", - column: x => x.PersonId, - principalTable: "Person", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); + constraints: table => + { + table.PrimaryKey("PK_PersonNote", x => x.Id); + table.ForeignKey( + name: "FK_PersonNote_Person_PersonId", + column: x => x.PersonId, + principalTable: "Person", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); migrationBuilder.CreateIndex( name: "IX_PersonNote_PersonId", diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.Designer.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.Designer.cs index a905d71..f77360b 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.Designer.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.Designer.cs @@ -1,4 +1,4 @@ -// +// using Benday.EfCore.SqlServer.TestApi; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -14,77 +14,77 @@ partial class Newsletters { protected override void BuildTargetModel(ModelBuilder modelBuilder) { -#pragma warning disable 612, 618 - modelBuilder + #pragma warning disable 612, 618 + modelBuilder .HasAnnotation("ProductVersion", "3.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.EmailNewsletterSubscription", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("EmailAddress") - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("EmailNewsletterSubscriptions"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("EmailNewsletterSubscriptions"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("FirstName") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("LastName") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("Person"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("NoteText") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("PersonId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("PersonId"); - - b.ToTable("PersonNote"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("NoteText") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonNote"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") - .WithMany("Notes") - .HasForeignKey("PersonId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 + { + b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") + .WithMany("Notes") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + #pragma warning restore 612, 618 } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.cs index a8faea8..9e139b1 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/20190926185308_Newsletters.cs @@ -11,13 +11,13 @@ protected override void Up(MigrationBuilder migrationBuilder) columns: table => new { Id = table.Column(nullable: false) - .Annotation("SqlServer:Identity", "1, 1"), + .Annotation("SqlServer:Identity", "1, 1"), EmailAddress = table.Column(nullable: true) }, - constraints: table => - { - table.PrimaryKey("PK_EmailNewsletterSubscriptions", x => x.Id); - }); + constraints: table => + { + table.PrimaryKey("PK_EmailNewsletterSubscriptions", x => x.Id); + }); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/TestDbContextModelSnapshot.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/TestDbContextModelSnapshot.cs index 000dba5..cf9e0b3 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/TestDbContextModelSnapshot.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Migrations/TestDbContextModelSnapshot.cs @@ -1,4 +1,4 @@ -// +// using Benday.EfCore.SqlServer.TestApi; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -12,77 +12,77 @@ partial class TestDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { -#pragma warning disable 612, 618 - modelBuilder + #pragma warning disable 612, 618 + modelBuilder .HasAnnotation("ProductVersion", "3.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.EmailNewsletterSubscription", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("EmailAddress") - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("EmailNewsletterSubscriptions"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("EmailNewsletterSubscriptions"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("FirstName") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("LastName") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("Person"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("NoteText") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("PersonId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("PersonId"); - - b.ToTable("PersonNote"); - }); - + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("NoteText") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonNote"); + }); + modelBuilder.Entity("Benday.EfCore.SqlServer.TestApi.PersonNote", b => - { - b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") - .WithMany("Notes") - .HasForeignKey("PersonId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 + { + b.HasOne("Benday.EfCore.SqlServer.TestApi.Person", "Person") + .WithMany("Notes") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + #pragma warning restore 612, 618 } } -} +} \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Person.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Person.cs index 07cfab1..ad71909 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Person.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/Person.cs @@ -1,12 +1,11 @@ -using Benday.Common; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Benday.EfCore.SqlServer.TestApi { [Table("Person")] - public class Person : IInt32Identity + public class Person : IEntityBase { public Person() { @@ -23,5 +22,16 @@ public Person() public string LastName { get; set; } public List Notes { get; set; } + + [NotMapped] + public bool IsMarkedForDelete + { + get; set; + } + + public IList GetDependentEntities() + { + return null; + } } -} \ No newline at end of file +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/PersonNote.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/PersonNote.cs index 0ce3930..4ca2f78 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/PersonNote.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/PersonNote.cs @@ -1,5 +1,5 @@ -using Benday.Common; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; +using Benday.Common; namespace Benday.EfCore.SqlServer.TestApi { @@ -16,4 +16,4 @@ public class PersonNote : IInt32Identity [Required] public string NoteText { get; set; } } -} \ No newline at end of file +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/SqlPersonRepository.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/SqlPersonRepository.cs index 2b24315..23a03f9 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/SqlPersonRepository.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/SqlPersonRepository.cs @@ -14,21 +14,16 @@ public SqlPersonRepository(TestDbContext context) : base(context) { } - protected override DbSet EntityDbSet - { - get - { - return Context.Persons; - } - } + protected override DbSet EntityDbSet => Context.Persons; protected override List Includes { get { - var includes = new List(); - - includes.Add(nameof(Person.Notes)); + var includes = new List + { + nameof(Person.Notes) + }; return includes; } @@ -59,7 +54,7 @@ protected override Expression> GetPredicateForContains(Search else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -91,7 +86,7 @@ protected override Expression> GetPredicateForDoesNotContain( else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -124,7 +119,7 @@ protected override Expression> GetPredicateForEndsWith(Search else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -156,7 +151,7 @@ protected override Expression> GetPredicateForEquals(SearchAr else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -188,7 +183,7 @@ protected override Expression> GetPredicateForIsNotEqualTo(Se else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -221,7 +216,7 @@ protected override Expression> GetPredicateForStartsWith(Sear else { throw new InvalidOperationException( - String.Format("Unknown argument '{0}'.", arg.PropertyName)); + string.Format("Unknown argument '{0}'.", arg.PropertyName)); } return returnValue; @@ -239,7 +234,7 @@ protected override IOrderedQueryable AddSortDescending(IOrderedQueryable else { return query.ThenByDescending(x => x.FirstName); - } + } } else if (propertyName == "LastName") { @@ -310,4 +305,4 @@ protected override IOrderedQueryable AddSortAscending(IOrderedQueryable< } } } -} \ No newline at end of file +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/TestDesignTimeDbContextFactory.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/TestDesignTimeDbContextFactory.cs index a4662ff..cd117da 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/TestDesignTimeDbContextFactory.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/TestDesignTimeDbContextFactory.cs @@ -1,22 +1,17 @@ -using Microsoft.EntityFrameworkCore; +using System; +using System.IO; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; namespace Benday.EfCore.SqlServer.TestApi { - public class TestDesignTimeDbContextFactory : - IDesignTimeDbContextFactory + IDesignTimeDbContextFactory { - public TestDbContext Create() + public static TestDbContext Create() { - var environmentName = - Environment.GetEnvironmentVariable( - "ASPNETCORE_ENVIRONMENT"); + var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var basePath = AppContext.BaseDirectory; @@ -30,19 +25,20 @@ public TestDbContext CreateDbContext(string[] args) Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); } - private TestDbContext Create(string basePath, string environmentName) + private static TestDbContext Create(string basePath, string environmentName) { var builder = new ConfigurationBuilder() .SetBasePath(basePath) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{environmentName}.json", true) + .AddJsonFile($"appsettings.unversioned.json", true) .AddEnvironmentVariables(); var config = builder.Build(); var connstr = config.GetConnectionString("default"); - if (String.IsNullOrWhiteSpace(connstr) == true) + if (string.IsNullOrWhiteSpace(connstr) == true) { throw new InvalidOperationException( "Could not find a connection string named 'default'."); @@ -53,19 +49,19 @@ private TestDbContext Create(string basePath, string environmentName) } } - private TestDbContext Create(string connectionString) + private static TestDbContext Create(string connectionString) { if (string.IsNullOrEmpty(connectionString)) throw new ArgumentException( - $"{nameof(connectionString)} is null or empty.", - nameof(connectionString)); + $"{nameof(connectionString)} is null or empty.", + nameof(connectionString)); var optionsBuilder = - new DbContextOptionsBuilder(); + new DbContextOptionsBuilder(); Console.WriteLine( - "TestDesignTimeDbContextFactory.Create(string): Connection string: {0}", - connectionString); + "TestDesignTimeDbContextFactory.Create(string): Connection string: {0}", + connectionString); optionsBuilder.UseSqlServer(connectionString); diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/appsettings.json b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/appsettings.json index 406b9b6..2f34264 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/appsettings.json +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.TestApi/appsettings.json @@ -1,4 +1,4 @@ -{ +{ "ConnectionStrings": { "default_windows": "Server=(local); Database=benday-efcore-sqlserver; Trusted_Connection=True;", "default_container": "Server=localhost; Database=benday-efcore-sqlserver; User Id=sa; Password=Pa$$word;", diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.csproj b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.csproj index 732fa1a..49417bc 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.csproj +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer.csproj @@ -1,11 +1,12 @@ - + - netstandard2.1 + net6.0 - - - + + + + \ No newline at end of file diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/DependentEntityCollection.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/DependentEntityCollection.cs new file mode 100644 index 0000000..d6c7b6c --- /dev/null +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/DependentEntityCollection.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; + +namespace Benday.EfCore.SqlServer +{ + public class DependentEntityCollection : + IDependentEntityCollection where T : class, IEntityBase + { + private readonly IList _entities; + + public DependentEntityCollection(IList entities) + { + _entities = entities ?? throw new ArgumentNullException(nameof(entities), "Argument cannot be null."); + } + + public void BeforeSave(DbContext dbContext) + { + foreach (var entity in _entities) + { + if (entity.IsMarkedForDelete == true) + { + RemoveFromDbSet(dbContext, entity); + } + } + } + + private void RemoveFromDbSet(DbContext dbContext, T entity) + { + dbContext.Remove(entity); + } + + public void AfterSave() + { + var deleteThese = _entities.Where(x => x.IsMarkedForDelete == true).ToList(); + + deleteThese.ForEach(x => _entities.Remove(x)); + } + } +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IDependentEntityCollection.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IDependentEntityCollection.cs new file mode 100644 index 0000000..28c8223 --- /dev/null +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IDependentEntityCollection.cs @@ -0,0 +1,10 @@ +using Microsoft.EntityFrameworkCore; + +namespace Benday.EfCore.SqlServer +{ + public interface IDependentEntityCollection + { + void AfterSave(); + void BeforeSave(DbContext dbContext); + } +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IEntityBase.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IEntityBase.cs new file mode 100644 index 0000000..55f742f --- /dev/null +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IEntityBase.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Benday.Common; + +namespace Benday.EfCore.SqlServer +{ + public interface IEntityBase : IInt32Identity, IDeleteable + { + IList GetDependentEntities(); + } +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IRepository.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IRepository.cs index fccb580..1fe8c68 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IRepository.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/IRepository.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Benday.Common; namespace Benday.EfCore.SqlServer @@ -7,7 +6,7 @@ namespace Benday.EfCore.SqlServer public interface IRepository where T : IInt32Identity { IList GetAll(); - IList GetAll(int maxNumberOfRows); + IList GetAll(int maxNumberOfRows, bool noIncludes = true); T GetById(int id); void Save(T saveThis); void Delete(T deleteThis); diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ISearchableRepository.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ISearchableRepository.cs index de4cfdf..3314a5c 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ISearchableRepository.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ISearchableRepository.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; -using Benday.Common; +using Benday.Common; namespace Benday.EfCore.SqlServer { - public interface ISearchableRepository : IRepository + public interface ISearchableRepository : IRepository where T : IInt32Identity { SearchResult Search(Search search); diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/LinqPredicateExtensions.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/LinqPredicateExtensions.cs index be5b675..c4825fb 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/LinqPredicateExtensions.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/LinqPredicateExtensions.cs @@ -24,7 +24,7 @@ private static Expression> Combine( Expression> right, ExpressionType expressionType) { - ParameterExpression leftParameter0 = left.Parameters[0]; + var leftParameter0 = left.Parameters[0]; var visitor = new ParameterSubstitutionVisitor(); diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ParameterSubstitutionVisitor.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ParameterSubstitutionVisitor.cs index 0727705..5b7c7b1 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ParameterSubstitutionVisitor.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/ParameterSubstitutionVisitor.cs @@ -5,8 +5,16 @@ namespace Benday.EfCore.SqlServer { public class ParameterSubstitutionVisitor : ExpressionVisitor { - public Dictionary Substitutions = - new Dictionary(); + public ParameterSubstitutionVisitor() + { + Substitutions = new Dictionary(); + } + + public Dictionary Substitutions + { + get; + private set; + } protected override Expression VisitParameter(ParameterExpression expr) { diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkCrudRepositoryBase.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkCrudRepositoryBase.cs index f43499f..355c557 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkCrudRepositoryBase.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkCrudRepositoryBase.cs @@ -1,21 +1,19 @@ -using Benday.Common; -using Microsoft.EntityFrameworkCore; -using System; +using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Text; +using Microsoft.EntityFrameworkCore; namespace Benday.EfCore.SqlServer { public abstract class SqlEntityFrameworkCrudRepositoryBase : SqlEntityFrameworkRepositoryBase, IRepository - where TEntity : class, IInt32Identity + where TEntity : class, IEntityBase where TDbContext : DbContext { public SqlEntityFrameworkCrudRepositoryBase( TDbContext context) : base(context) { - } protected abstract DbSet EntityDbSet @@ -46,12 +44,10 @@ public virtual void Delete(TEntity deleteThis) protected virtual void BeforeDelete(TEntity deleteThis) { - } protected virtual void AfterDelete(TEntity deleteThis) { - } protected virtual List Includes @@ -61,13 +57,7 @@ protected virtual List Includes public virtual IList GetAll() { - var queryable = EntityDbSet.AsQueryable(); - - queryable = AddIncludes(queryable); - - queryable = BeforeGetAll(queryable); - - return queryable.ToList(); + return GetAll(-1, true); } protected virtual IQueryable BeforeGetAll(IQueryable query) @@ -75,14 +65,33 @@ protected virtual IQueryable BeforeGetAll(IQueryable query) return query; } - public virtual IList GetAll(int maxNumberOfRows) + protected virtual IQueryable AddDefaultSort(IQueryable query) + { + return query; + } + + public virtual IList GetAll(int maxNumberOfRows, bool noIncludes) { var queryable = EntityDbSet.AsQueryable(); - queryable = AddIncludes(queryable); + if (noIncludes == false) + { + queryable = AddIncludes(queryable); + } + + queryable = BeforeGetAll(queryable); + + queryable = AddDefaultSort(queryable); - return queryable.Take(maxNumberOfRows).ToList(); - } + if (maxNumberOfRows == -1) + { + return queryable.ToList(); + } + else + { + return queryable.Take(maxNumberOfRows).ToList(); + } + } protected virtual IQueryable AddIncludes(IQueryable queryable) { @@ -119,6 +128,7 @@ public virtual TEntity GetById(int id) return query.FirstOrDefault(); } + [SuppressMessage("csharp", "IDE0060")] private IQueryable BeforeGetById(IQueryable query, int id) { return query; @@ -134,19 +144,57 @@ public virtual void Save(TEntity saveThis) BeforeSave(saveThis); + BeforeSaveOnDependentEntities(saveThis); + Context.SaveChanges(); + AfterSaveOnDependentEntities(saveThis); AfterSave(saveThis); } - protected virtual void BeforeSave(TEntity saveThis) + private void AfterSaveOnDependentEntities(TEntity saveThis) { + var dependentEntityCollections = saveThis.GetDependentEntities(); + if (dependentEntityCollections == null || + dependentEntityCollections.Count == 0) + { + return; + } + else + { + foreach (var item in dependentEntityCollections) + { + item.AfterSave(); + } + } } - protected virtual void AfterSave(TEntity saveThis) + protected virtual void BeforeSaveOnDependentEntities( + TEntity saveThis) + { + var dependentEntityCollections = saveThis.GetDependentEntities(); + + if (dependentEntityCollections == null || + dependentEntityCollections.Count == 0) + { + return; + } + else + { + foreach (var item in dependentEntityCollections) + { + item.BeforeSave(Context); + } + } + } + + protected virtual void BeforeSave(TEntity saveThis) { + } + protected virtual void AfterSave(TEntity saveThis) + { } } } diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkRepositoryBase.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkRepositoryBase.cs index 33880d1..468f101 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkRepositoryBase.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkRepositoryBase.cs @@ -1,62 +1,66 @@ -using Benday.Common; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; - -namespace Benday.EfCore.SqlServer -{ - public abstract class SqlEntityFrameworkRepositoryBase : - IDisposable where TEntity : class, IInt32Identity - where TDbContext : DbContext - { - public SqlEntityFrameworkRepositoryBase( - TDbContext context) - { - if (context == null) - throw new ArgumentNullException("context", "context is null."); - - _Context = context; - } - - public void Dispose() - { - ((IDisposable)_Context).Dispose(); - } - - private TDbContext _Context; - - protected TDbContext Context - { - get - { - return _Context; - } - } - - protected void VerifyItemIsAddedOrAttachedToDbSet(DbSet dbset, TEntity item) - { - if (item == null) - { - return; - } - else - { - if (item.Id == 0) - { - dbset.Add(item); - } - else - { - var entry = _Context.Entry(item); - - if (entry.State == EntityState.Detached) - { - dbset.Attach(item); - } - - entry.State = EntityState.Modified; - } - } - } - } -} +using System; +using Microsoft.EntityFrameworkCore; + +namespace Benday.EfCore.SqlServer +{ + public abstract class SqlEntityFrameworkRepositoryBase : + IDisposable where TEntity : class, IEntityBase + where TDbContext : DbContext + { + protected SqlEntityFrameworkRepositoryBase( + TDbContext context) + { + _context = context ?? throw new ArgumentNullException("context", "context is null."); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private bool _isDisposed = false; + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) return; + + if (disposing) + { + // free managed resources + ((IDisposable)_context).Dispose(); + } + + _isDisposed = true; + } + + private readonly TDbContext _context; + + protected TDbContext Context => _context; + + protected void VerifyItemIsAddedOrAttachedToDbSet(DbSet dbset, TEntity item) + { + if (item == null) + { + return; + } + else + { + if (item.Id == 0) + { + dbset.Add(item); + } + else + { + var entry = _context.Entry(item); + + if (entry.State == EntityState.Detached) + { + dbset.Attach(item); + } + + entry.State = EntityState.Modified; + } + } + } + } +} diff --git a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkSearchableRepositoryBase.cs b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkSearchableRepositoryBase.cs index d12d381..a9eeffd 100644 --- a/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkSearchableRepositoryBase.cs +++ b/Benday.EfCore.SqlServer/Benday.EfCore.SqlServer/SqlEntityFrameworkSearchableRepositoryBase.cs @@ -1,28 +1,28 @@ -using Benday.Common; -using Microsoft.EntityFrameworkCore; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using Benday.Common; +using Microsoft.EntityFrameworkCore; namespace Benday.EfCore.SqlServer { public abstract class SqlEntityFrameworkSearchableRepositoryBase : SqlEntityFrameworkCrudRepositoryBase, ISearchableRepository - where TEntity : class, IInt32Identity + where TEntity : class, IEntityBase where TDbContext : DbContext { public SqlEntityFrameworkSearchableRepositoryBase( TDbContext context) : base(context) { - } public virtual SearchResult Search(Search search) { - var returnValue = new SearchResult(); - - returnValue.SearchRequest = search; + var returnValue = new SearchResult + { + SearchRequest = search + }; if (search == null) { @@ -30,11 +30,9 @@ public virtual SearchResult Search(Search search) } else { - Expression> whereClausePredicate = null; - whereClausePredicate = GetWhereClause(search); - - IQueryable query = null; + var whereClausePredicate = GetWhereClause(search); + IQueryable query; if (whereClausePredicate == null) { query = EntityDbSet.AsQueryable(); @@ -108,7 +106,7 @@ protected virtual IQueryable AddSorts(Search search, IQueryable AddSorts(Search search, IQueryable> GetWhereClause(Search search) if (predicate == null) { - // if predicate is null, the implementer chose to ignore this + // if predicate is null, the implementer chose to ignore this // search argument and returned null as an indication to skip continue; } @@ -190,7 +188,7 @@ private Expression> GetWhereClause(Search search) else { throw new InvalidOperationException( - String.Format("Search operator '{0}' is not supported.", arg.Operator)); + string.Format("Search operator '{0}' is not supported.", arg.Operator)); } } @@ -213,6 +211,6 @@ protected abstract Expression> GetPredicateForEndsWith( protected abstract Expression> GetPredicateForStartsWith( SearchArgument arg); protected abstract Expression> GetPredicateForContains( - SearchArgument arg); + SearchArgument arg); } } diff --git a/Benday.JsonUtilities/Benday.JsonUtilities.csproj b/Benday.JsonUtilities/Benday.JsonUtilities.csproj index a78938c..345f009 100644 --- a/Benday.JsonUtilities/Benday.JsonUtilities.csproj +++ b/Benday.JsonUtilities/Benday.JsonUtilities.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net6.0 diff --git a/Benday.JsonUtilities/JsonEditor.cs b/Benday.JsonUtilities/JsonEditor.cs index 806f6d1..5b36686 100644 --- a/Benday.JsonUtilities/JsonEditor.cs +++ b/Benday.JsonUtilities/JsonEditor.cs @@ -1,28 +1,27 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; +using System; using System.IO; using System.Linq; using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Benday.JsonUtilities { public class JsonEditor { - private JObject _Json; - private string _PathToFile; + private readonly JObject _json; + private readonly string _pathToFile; public JsonEditor(string pathToFile) { if (string.IsNullOrEmpty(pathToFile)) throw new ArgumentException($"{nameof(pathToFile)} is null or empty.", nameof(pathToFile)); - _PathToFile = pathToFile; + _pathToFile = pathToFile; - AssertFileExists(_PathToFile); + AssertFileExists(_pathToFile); - _Json = LoadJsonFromFile(_PathToFile); + _json = LoadJsonFromFile(_pathToFile); } public JsonEditor(string json, bool loadFromString) @@ -35,9 +34,9 @@ public JsonEditor(string json, bool loadFromString) if (string.IsNullOrEmpty(json)) throw new ArgumentException($"{nameof(json)} is null or empty.", nameof(json)); - _PathToFile = null; + _pathToFile = null; - _Json = JObject.Parse(json); + _json = JObject.Parse(json); } public JsonEditor(JObject fromObject) @@ -47,14 +46,14 @@ public JsonEditor(JObject fromObject) throw new ArgumentException($"{nameof(fromObject)} is null or empty.", nameof(fromObject)); } - _Json = fromObject; + _json = fromObject; } public string GetValue(params string[] nodes) { if (nodes == null || nodes.Length == 0) throw new ArgumentException( - $"{nameof(nodes)} is null or empty.", nameof(nodes)); + $"{nameof(nodes)} is null or empty.", nameof(nodes)); var query = GetJsonQueryForNodes(nodes); return GetValueUsingQuery(query.ToString()); @@ -62,7 +61,7 @@ public string GetValue(params string[] nodes) private string GetJsonQueryForNodes(params string[] nodes) { - bool needsPeriod = false; + var needsPeriod = false; var query = new StringBuilder(); @@ -88,9 +87,9 @@ private void CreateNodeStructure(string[] nodes) JObject parent = null; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { - var current = GetJToken(_Json, + var current = GetJToken(_json, GetJsonQueryForNodes(nodes.Take(i + 1).ToArray())); if (current == null) @@ -98,12 +97,12 @@ private void CreateNodeStructure(string[] nodes) if ((nodes.Length - i) > 1) { // node is somewhere in the middle of structure - JObject tempContainer = new JObject(); + var tempContainer = new JObject(); var temp = new JProperty(nodes[i], tempContainer); if (parent == null) { - _Json.Add(temp); + _json.Add(temp); } else { @@ -115,11 +114,11 @@ private void CreateNodeStructure(string[] nodes) else { // end of node structure - var temp = new JProperty(nodes[i], String.Empty); + var temp = new JProperty(nodes[i], string.Empty); if (parent == null) { - _Json.Add(temp); + _json.Add(temp); } else { @@ -140,11 +139,11 @@ public void SetValue(string nodeValue, params string[] nodes) throw new ArgumentException($"{nameof(nodeValue)} is null or empty.", nameof(nodeValue)); if (nodes == null || nodes.Length == 0) throw new ArgumentException( - $"{nameof(nodes)} is null or empty.", nameof(nodes)); + $"{nameof(nodes)} is null or empty.", nameof(nodes)); var query = GetJsonQueryForNodes(nodes); - var match = GetJToken(_Json, query); + var match = GetJToken(_json, query); if (match != null) { @@ -159,35 +158,19 @@ public void SetValue(string nodeValue, params string[] nodes) WriteJsonFile(); } - private void SetValueUsingQuery(string query, string value) - { - var match = GetJToken(_Json, query); - - if (match != null) - { - match.Replace(new JValue(value)); - } - else - { - throw new InvalidOperationException("No matching node."); - } - - WriteJsonFile(); - } - private void WriteJsonFile() { - if (_PathToFile != null) + if (_pathToFile != null) { File.WriteAllText( - _PathToFile, - JsonConvert.SerializeObject(_Json, Formatting.Indented)); + _pathToFile, + JsonConvert.SerializeObject(_json, Formatting.Indented)); } } public string ToJsonString() { - return JsonConvert.SerializeObject(_Json, Formatting.Indented); + return JsonConvert.SerializeObject(_json, Formatting.Indented); } private JToken GetJToken(JObject json, string query) @@ -197,17 +180,10 @@ private JToken GetJToken(JObject json, string query) return match; } - private List GetJTokens(JObject json, string query) - { - var match = json.SelectTokens(query).ToList(); - - return match; - } - private string GetValueUsingQuery(string query) { - JToken match = GetJToken( - _Json, query); + var match = GetJToken( + _json, query); if (match == null) { @@ -279,11 +255,11 @@ public JToken GetNode(params string[] nodes) { if (nodes == null || nodes.Length == 0) throw new ArgumentException( - $"{nameof(nodes)} is null or empty.", nameof(nodes)); + $"{nameof(nodes)} is null or empty.", nameof(nodes)); var query = GetJsonQueryForNodes(nodes); - return GetJToken(_Json, query); + return GetJToken(_json, query); } public JToken GetNodeByQuery(string query) @@ -293,13 +269,13 @@ public JToken GetNodeByQuery(string query) throw new ArgumentException($"{nameof(query)} is null or empty.", nameof(query)); } - return GetJToken(_Json, query); + return GetJToken(_json, query); } private JToken FindParentNodeBySiblingValue(SiblingValueArguments args) { var collectionMatch = GetJToken( - _Json, GetJsonQueryForNodes(args.PathArguments)); + _json, GetJsonQueryForNodes(args.PathArguments)); if (collectionMatch == null) { @@ -329,6 +305,5 @@ private JToken FindParentNodeBySiblingValue(SiblingValueArguments args) return null; } } - } } diff --git a/Benday.JsonUtilities/JsonEditorUtility.cs b/Benday.JsonUtilities/JsonEditorUtility.cs index 728a894..de49818 100644 --- a/Benday.JsonUtilities/JsonEditorUtility.cs +++ b/Benday.JsonUtilities/JsonEditorUtility.cs @@ -1,11 +1,7 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; +using System; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Benday.JsonUtilities { @@ -80,7 +76,7 @@ public static void SetValue( if (string.IsNullOrEmpty(value)) throw new ArgumentException($"{nameof(value)} is null or empty.", nameof(value)); - string query = String.Format("{0}.{1}", node1, node2); + var query = string.Format("{0}.{1}", node1, node2); SetValueUsingQuery(pathToFile, query, value); } @@ -100,7 +96,7 @@ public static void SetValue( if (string.IsNullOrEmpty(value)) throw new ArgumentException($"{nameof(value)} is null or empty.", nameof(value)); - string query = String.Format("{0}.{1}.{2}", + var query = string.Format("{0}.{1}.{2}", node1, node2, node3); SetValueUsingQuery(pathToFile, query, value); @@ -121,7 +117,7 @@ private static void SetValueUsingQuery( var json = LoadJsonFile(pathToFile); - var match = GetJToken(json, pathToFile, query); + var match = GetJToken(json, query); if (match != null) { @@ -140,9 +136,9 @@ private static string GetValueUsingQuery(string pathToFile, string query) { var tempJObject = LoadJsonFile(pathToFile); - JToken match = GetJToken( + var match = GetJToken( tempJObject, - pathToFile, query); + query); if (match == null) { @@ -154,7 +150,7 @@ private static string GetValueUsingQuery(string pathToFile, string query) } } - public static JToken GetJToken(JObject json, string pathToFile, string query) + public static JToken GetJToken(JObject json, string query) { var match = json.SelectToken(query); @@ -185,7 +181,5 @@ public static string BeautifyJson(string input) dynamic parsedJson = JsonConvert.DeserializeObject(input); return JsonConvert.SerializeObject(parsedJson, Formatting.Indented); } - - } } diff --git a/Benday.JsonUtilities/SiblingValueArguments.cs b/Benday.JsonUtilities/SiblingValueArguments.cs index 32b7f8c..d4f9769 100644 --- a/Benday.JsonUtilities/SiblingValueArguments.cs +++ b/Benday.JsonUtilities/SiblingValueArguments.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; - -namespace Benday.JsonUtilities +namespace Benday.JsonUtilities { public class SiblingValueArguments {