public void TestCreateBookAndCheckPartsOk() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <SqlEventsDbContext>(x => _output.WriteLine(x.Message)); using (var context = new SqlEventsDbContext(options, null)) { context.Database.EnsureCreated(); var book = WithEventsEfTestData.CreateDummyBookTwoAuthorsTwoReviews(); context.Add(book); context.SaveChanges(); } using (var context = new SqlEventsDbContext(options, null)) { //ATTEMPT var bookWithRelationships = context.Books .Include(p => p.AuthorsLink).ThenInclude(p => p.Author) .Include(p => p.Reviews) .Single(); //VERIFY bookWithRelationships.AuthorsLink.Select(y => y.Author.Name).OrderBy(x => x).ToArray() .ShouldEqual(new[] { "Author1", "Author2" }); bookWithRelationships.Reviews.Count().ShouldEqual(2); } }
public void TestDbQueryChildReadOnlyOk() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <TestDbContext>(log => _output.WriteLine(log.ToString())); using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); #if NETCOREAPP3_0 context.ExecuteScriptFileInTransaction(TestData.GetFilePath("ReplaceTableWithView.sql")); #endif context.Add(new Parent { Children = new List <Child> { new Child { MyString = "Hello" }, new Child { MyString = "Goodbye" } } }); context.SaveChanges(); } using (var context = new TestDbContext(options)) { //ATTEMPT var children = context.Children.ToList(); //VERIFY children.Count.ShouldEqual(2); } }
public void TestAverageDirectOk() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); } using (var context = new EfCoreContext(options)) { //ATTEMPT showLog = true; var averages = context.Books.Select(p => p.Reviews.Count == 0 ? null : (decimal?)p.Reviews.Select(q => q.NumStars).Average()).ToList(); //VERIFY averages.Count(x => x == null).ShouldEqual(3); averages.Count(x => x != null).ShouldEqual(1); } }
public void TestDisconnectedCascadeSoftDeleteEmployeeSoftDelOk(bool readEveryTime) { //SETUP var logs = new List <string>(); var options = SqliteInMemory.CreateOptionsWithLogging <CascadeSoftDelDbContext>(log => logs.Add(log.DecodeMessage())); using (var context = new CascadeSoftDelDbContext(options)) { context.Database.EnsureCreated(); Employee.SeedEmployeeSoftDel(context); } using (var context = new CascadeSoftDelDbContext(options)) { var config = new ConfigCascadeDeleteWithUserId(context) { ReadEveryTime = readEveryTime }; var service = new CascadeSoftDelService <ICascadeSoftDelete>(context, config); //ATTEMPT logs.Clear(); var status = service.SetCascadeSoftDelete(context.Employees.Single(x => x.Name == "CTO")); //VERIFY status.IsValid.ShouldBeTrue(status.GetAllErrors()); logs.Count(x => _selectMatchRegex.IsMatch(x)).ShouldEqual(7); status.Result.ShouldEqual(7 + 6); context.Employees.Count().ShouldEqual(4); context.Employees.IgnoreQueryFilters().Count().ShouldEqual(11); context.Contracts.Count().ShouldEqual(3); context.Contracts.IgnoreQueryFilters().Count().ShouldEqual(9); } }
public void TestAddReviewToCreatedBookAndCheckReviewAddedHandlerOk() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <SqlEventsDbContext>(x => { if (showLog) { _output.WriteLine(x.DecodeMessage()); } }); var context = options.CreateDbWithDiForHandlers <SqlEventsDbContext, ReviewAddedHandler>(); context.Database.EnsureCreated(); var book = WithEventsEfTestData.CreateDummyBookOneAuthor(); context.Add(book); context.SaveChanges(); //ATTEMPT showLog = true; book.AddReview(4, "OK", "me"); context.SaveChanges(); //VERIFY book.ReviewsCount.ShouldEqual(1); book.ReviewsAverageVotes.ShouldEqual(4); }
public void TestEagerLoadBookAndReviewOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); } using (var context = new EfCoreContext(options)) { //ATTEMPT showlog = true; var firstBook = context.Books .Include(book => book.Reviews) //#A .First(); //#B /********************************************************* #A The Include() gets a collection of Reviews, which may be an empty collection #B This takes the first book * *******************************************************/ //VERIFY firstBook.Reviews.ShouldNotBeNull(); firstBook.AuthorsLink.ShouldBeNull(); } }
public void TestEfCoreLoggingStringWithBadValues() { //SETUP var logs = new List <LogOutput>(); #pragma warning disable 618 var options = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs.Add(log)); #pragma warning restore 618 using (var context = new BookContext(options)) { context.Database.EnsureCreated(); //ATTEMPT context.Books.Count(); context.Add(new Book { Title = "The person's boss said, \"What's that about?\"" }); context.SaveChanges(); //VERIFY foreach (var log in logs.ToList()) { _output.WriteLine(log.ToString()); } } }
public void TestDecodeMessageNoParams() { //SETUP var logs = new List <LogOutput>(); #pragma warning disable 618 var options = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs.Add(log)); #pragma warning restore 618 //var options = this.CreateUniqueClassOptionsWithLogging<BookContext>(log => logs.Add(log)); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); //ATTEMPT context.Books.Count(); var decoded = logs.Last().DecodeMessage(); //VERIFY var sqlCommand = decoded.Split('\n').Skip(1).Select(x => x.Trim()).ToArray(); sqlCommand[0].ShouldEqual("SELECT COUNT(*)"); sqlCommand[1].ShouldEqual("FROM \"Books\" AS \"b\""); sqlCommand[2].ShouldEqual("WHERE NOT (\"b\".\"SoftDeleted\")"); } }
public void TestCreateOneEntryWithLogs() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <Chapter3DbContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using (var context = new Chapter3DbContext(options)) { context.Database.EnsureCreated(); showLog = true; var itemToAdd = new ExampleEntity { MyMessage = "Hello World" }; //ATTEMPT context.SingleEntities.Add( itemToAdd); context.SaveChanges(); //VERIFY context.SingleEntities.Count().ShouldEqual(1); } }
public void TestCountReviewsGoodOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using var context = new EfCoreContext(options); context.Database.EnsureCreated(); var bookWithReviews = context.SeedDatabaseFourBooks().First(x => x.Reviews?.Any() ?? false); bookWithReviews.SoftDeleted = true; context.SaveChanges(); context.ChangeTracker.Clear(); //ATTEMPT showlog = true; var numReviews = context.Books.SelectMany(x => x.Reviews).Count(); //VERIFY numReviews.ShouldEqual(0); }
public void TestDeletePriceOfferWithLogging() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); var numPromotions = context.PriceOffers.Count(); //ATTEMPT showLog = true; var promotion = context.PriceOffers //#A .First(); //#A context.PriceOffers.Remove(promotion); //#B context.SaveChanges(); //#C showLog = false; //VERIFY context.PriceOffers.Count().ShouldEqual(numPromotions - 1); } }
public void UpdateTwoPropertiesWithLogging() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); //ATTEMPT showLog = true; var book = context.Books .Single(p => p.Title == "Quantum Networking"); book.Title = "New title"; book.PublishedOn = new DateTime(2058, 1, 1); context.SaveChanges(); showLog = false; //VERIFY var bookAgain = context.Books .Single(p => p.Title == "New title"); bookAgain.PublishedOn .ShouldEqual(new DateTime(2058, 1, 1)); } }
public void TestSimpleHandCodedOk() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); var lastBook = context.SeedDatabaseFourBooks().Last(); //ATTEMPT showLog = true; var dto = context.Books .Select(p => new ChangePubDateDto { BookId = p.BookId, Title = p.Title, PublishedOn = p.PublishedOn }) .Single(k => k.BookId == lastBook.BookId); //VERIFY dto.BookId.ShouldEqual(lastBook.BookId); dto.Title.ShouldEqual(lastBook.Title); dto.PublishedOn.ShouldEqual(lastBook.PublishedOn); } }
public void TestEfCoreLoggingWithMultipleDbContexts() { //SETUP var logs1 = new List <LogOutput>(); var options1 = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs1.Add(log)); var logs2 = new List <LogOutput>(); var options2 = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs2.Add(log)); using (var context1 = new BookContext(options1)) using (var context2 = new BookContext(options2)) { //ATTEMPT context1.Database.EnsureCreated(); var logs1Count = logs1.Count; context2.Database.EnsureCreated(); //VERIFY logs1.Count.ShouldEqual(logs1Count); #if NETCOREAPP2_1 logs2.Count.ShouldEqual(logs1Count); #elif NETCOREAPP3_0 logs2.Count.ShouldBeInRange(logs1Count - 1, logs1Count + 1); //It depends which one starts first #endif } }
public void TestSimpleAutoMapperOk() { //SETUP var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); var lastBook = context.SeedDatabaseFourBooks().Last(); var config = CreateMapperConfigScanTestAutoMap(); //ATTEMPT showLog = true; var dto = context.Books .ProjectTo <ChangePubDateDtoAm>(config) .Single(x => x.BookId == lastBook.BookId); //VERIFY dto.BookId.ShouldEqual(lastBook.BookId); dto.Title.ShouldEqual(lastBook.Title); dto.PublishedOn.ShouldEqual(lastBook.PublishedOn); } }
public void TestCheckoutListTwoBooksSqLite() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); var dbAccess = new PlaceOrderDbAccess(context); //ATTEMPT showlog = true; var booksDict = dbAccess.FindBooksByIdsWithPriceOffers(new [] { 1, 4 }); //VERIFY booksDict.Count.ShouldEqual(2); booksDict[1].Promotion.ShouldBeNull(); booksDict[4].Promotion.ShouldNotBeNull(); } }
public void UpdateAuthorWithLogging() { //SETUP string json; var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); var author = context.Books //#A .Where(p => p.Title == "Quantum Networking") //#A .Select(p => p.AuthorsLink.First().Author) //#A .Single(); //#A author.Name = "Future Person 2"; //#A json = JsonConvert.SerializeObject(author, //#A new JsonSerializerSettings() //#A { PreserveReferencesHandling = PreserveReferencesHandling.Objects //#A }); //#A } using (var context = new EfCoreContext(options)) { showLog = true; //ATTEMPT var author = JsonConvert .DeserializeObject <Author>(json); //#B context.Update(author); //#C context.SaveChanges(); //#D /********************************************************** #A This simulates an external system returning a modified Author entity class as a JSON string #B This simulates receiving a JSON string from an external system and decoding it into an Author class #C I use the Update command, which replaces all the row data for the given primary key, in this case AuthorId * *******************************************************/ //VERIFY var authorAgain = context.Books.Where(p => p.Title == "Quantum Networking") .Select(p => p.AuthorsLink.First().Author) .Single(); authorAgain.Name.ShouldEqual("Future Person 2"); context.Authors.Any(p => p.Name == "Future Person").ShouldBeFalse(); } }
public void TestBookQueryWithSeparateIncludes() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <Chapter06Context>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddManyTopWithRelationsToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var dummy1 = context.ManyTops.ToList(); var dummy2 = context.ManyTops.ToList(); ManyTop result; using (new TimeThings(_output, "sync load - first time")) { result = context.ManyTops.Single(); //#A var a = context.Set <Many1>() //#B .Where(x => x.ManyTopId == result.Id).ToList(); //#B var b = context.Set <Many2>() //#B .Where(x => x.ManyTopId == result.Id).ToList(); //#B var c = context.Set <Many3>() //#B .Where(x => x.ManyTopId == result.Id).ToList(); //#B /********************************************************* #A This read in the main entity class, ManyTop that the relationships link to first #B Then you read in the collections one by one. Relational fixup will fill in the navigational properties in the main entity class, ManyTop **********************************************************/ } using (new TimeThings(_output, "sync load - second time")) { result = context.ManyTops.Single(); var loadRels = new { a = context.Set <Many1>().Where(x => x.ManyTopId == result.Id).ToList(), b = context.Set <Many2>().Where(x => x.ManyTopId == result.Id).ToList(), c = context.Set <Many3>().Where(x => x.ManyTopId == result.Id).ToList(), }; } //VERIFY result.Collection1.Count.ShouldEqual(100); result.Collection2.Count.ShouldEqual(100); result.Collection3.Count.ShouldEqual(100); } }
public void TestReplaceReviewsLoggedOk() { //SETUP int twoReviewBookId; var showLog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showLog) { _output.WriteLine(log.DecodeMessage()); } }); using var context = new EfCoreContext(options); context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); twoReviewBookId = context.Books.ToList().Last().BookId; //Last has reviews context.ChangeTracker.Clear(); //ATTEMPT showLog = true; var book = context.Books .Include(p => p.Reviews) //#A .Single(p => p.BookId == twoReviewBookId); //#B book.Reviews = new List <Review> //#C { //#C new Review //#C { //#C VoterName = "Unit Test", //#C NumStars = 5, //#C } //#C }; //#C context.SaveChanges(); //#D /******************************************************* #A This include is important; this will create a collection with any existing reviews in it, or an empty collection if there aren't any existing reviews. #B This book I am loading has two review #C I completely replace the whole collection #D SaveChanges, via DetectChanges knows that a) the old collection should be deleted, b) the new collection should be written to the database * ******************************************************/ //VERIFY var bookAgain = context.Books .Include(p => p.Reviews) .Single(p => p.BookId == book.BookId); bookAgain.Reviews.ShouldNotBeNull(); bookAgain.Reviews.Count.ShouldEqual(1); context.Set <Review>().Count().ShouldEqual(1); }
public void TestBookQueryWithSeparateIncludes() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <Chapter06Context>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddManyTopWithRelationsToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var dummy1 = context.ManyTops.ToList(); var dummy2 = context.ManyTops.ToList(); ManyTop result; var id = 1; using (new TimeThings(_output, "sync load - first time")) { result = context.ManyTops .AsSplitQuery() //#A .Include(x => x.Collection1) .Include(x => x.Collection2) .Include(x => x.Collection3) .Single(x => x.Id == id); /********************************************************* #A This will cause each Include to be loaded separately, thus stopping the multiplication problem **********************************************************/ } using (new TimeThings(_output, "sync load - second time")) { result = context.ManyTops .AsSplitQuery() .Include(x => x.Collection1) .Include(x => x.Collection2) .Include(x => x.Collection3) .Single(); } //VERIFY result.Collection1.Count.ShouldEqual(100); result.Collection2.Count.ShouldEqual(100); result.Collection3.Count.ShouldEqual(100); } }
public void TestCreateDataSqliteInMemoryOk() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => _output.WriteLine(log.Message)); using (var context = new EfCoreContext(options)) { //ATTEMPT context.Database.EnsureCreated(); //VERIFY } }
public void TestCreateDatabaseAndSeedOk() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <SqlEventsDbContext>(x => _output.WriteLine(x.Message)); using (var context = new SqlEventsDbContext(options, null)) { context.Database.EnsureCreated(); //ATTEMPT context.SeedDatabaseFourBooks(); //VERIFY context.Books.Count().ShouldEqual(4); } }
public void TestEfCoreLoggingCheckSqlOutput() { //SETUP var logs = new List <LogOutput>(); var options = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs.Add(log)); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); //ATTEMPT context.Books.Count(); //VERIFY logs.Last().Message.ShouldEndWith("SELECT COUNT(*)\r\nFROM \"Books\" AS \"p\"\r\nWHERE \"p\".\"SoftDeleted\" = 0"); } }
public void TestEfCoreLoggingExampleOfOutputToConsole() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <BookContext>(l => _output.WriteLine(l.Message)); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); //ATTEMPT var books = context.Books.ToList(); //VERIFY } }
public void TestLazyLoadBookAndReviewUsingILazyLoaderOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <Lazy1DbContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new Lazy1DbContext(options)) { context.Database.EnsureCreated(); var book = new BookLazy1 { Reviews = new List <LazyReview> { new LazyReview { NumStars = 5 }, new LazyReview { NumStars = 1 } } }; context.Add(book); context.SaveChanges(); } using (var context = new Lazy1DbContext(options)) { //ATTEMPT showlog = true; var book = context.BookLazy1s.Single(); //#A var reviews = book.Reviews.ToList(); //#B /********************************************************* #A This gets an instance of the BookLazy entity class that has configured its Reviews property to use lazy loading #B When the Reviews property is accessed, then EF Core will read in the reviews from the database * *******************************************************/ //VERIFY reviews.Count.ShouldEqual(2); } }
public void TestLazyLoadBookAndReviewUsingActionOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <LazyInjectContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new LazyInjectContext(options)) { context.Database.EnsureCreated(); var book = new BookLazy2 { Promotion = new PriceOffer { NewPrice = 5 }, Reviews = new List <Lazy2Review> { new Lazy2Review { NumStars = 5 }, new Lazy2Review { NumStars = 1 } } }; context.Add(book); context.SaveChanges(); } using (var context = new LazyInjectContext(options)) { //ATTEMPT showlog = true; var book = context.BookLazy2s.Single(); var reviews = book.Reviews.ToList(); //VERIFY book.Promotion.ShouldBeNull(); context.BookLazy2s.Select(x => x.Promotion).ShouldNotBeNull(); reviews.Count.ShouldEqual(2); } }
public void TestBookListDtoSelect() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogging <SqlDbContext>(x => _output.WriteLine(x.Message)); using (var context = new SqlDbContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); //ATTEMPT var dtos = context.Books.MapBookToDto().OrderBy(x => x.PublishedOn).ToList(); //VERIFY dtos.Select(x => x.AuthorsOrdered).ShouldEqual(new [] { "Martin Fowler", "Martin Fowler", "Eric Evans", "Future Person" }); dtos.Select(x => x.ReviewsAverageVotes).ShouldEqual(new double? [] { null, null, null, 5 }); } }
public void TestSelectLoadBookOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); } using (var context = new EfCoreContext(options)) { //ATTEMPT showlog = true; var books = context.Books .Select(book => new //#A { //#A book.Title, //#B book.Price, //#B NumReviews //#C = book.Reviews.Count, //#C } ).ToList(); /********************************************************* #A This uses the LINQ select keyword and creates an anonymous type to hold the results #B These are simple copies of a couple of properties #C This runs a query that counts the number of reviews * *******************************************************/ //VERIFY showlog = false; books.First().NumReviews.ShouldEqual(0); } }
public void TestRightWayToSetupRelationshipsOk() { //SETUP var showlog = false; var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log => { if (showlog) { _output.WriteLine(log.Message); } }); using (var context = new EfCoreContext(options)) { context.Database.EnsureCreated(); showlog = true; //ATTEMPT var book = new Book //#A { //#A Title = "Test", //#A Reviews = new List <Review>() //#A }; //#A book.Reviews.Add( //#B new Review { NumStars = 1 }); //#B context.Add(book); //#C context.SaveChanges(); //#D /********************************************************* #A This creates a new Book #B This adds a new Review to the Book's Reviews navigational property #C The Add method says that the entity instance should be Added to the appropriate row, with any relationships either added or updated #D The SaveChanges carries out the database update *********************************************************/ //VERIFY var bookWithReview = context.Books.Include(x => x.Reviews).Single(); bookWithReview.Reviews.Count.ShouldEqual(1); } }
public void TestEfCoreLogging1() { //SETUP var logs = new List <LogOutput>(); var options = SqliteInMemory.CreateOptionsWithLogging <BookContext>(log => logs.Add(log)); using (var context = new BookContext(options)) { //ATTEMPT context.Database.EnsureCreated(); //VERIFY foreach (var log in logs) { _output.WriteLine(log.ToString()); } logs.Count.ShouldBeInRange(11, 50); } }