public void TestLoadByRoleDbShowQuery() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var query = context.Employees .Include(x => x.WorksForMe) .Where(x => x.WhatTheyDo.HasFlag(Roles.Development)); var devDept = query.ToList(); //VERIFY _output.WriteLine(query.ToQueryString()); devDept.Count.ShouldEqual(7); var cto = devDept.Single(x => x.Manager == null); cto.ShowHierarchical(s => _output.WriteLine(s)); } }
public void TestLoadByRoleDb() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var devDept = context.Employees //#A .Include(x => x.WorksForMe) //#B .Where(x => x.WhatTheyDo.HasFlag(Roles.Development)) //#C .ToList(); /******************************************************** #A The database holds all the Employees #B One Include is all that you need - relational fixup will work out what is linked to what #C This filters the employees down to ones that work in Development **********************************************/ //VERIFY devDept.Count.ShouldEqual(7); } }
public void TestDetachAllTrackedEntities(int numCollection) { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); var entityToDetach = context.AddManyTopWithRelationsToDb(); //ATTEMPT using (new TimeThings(_output, $"detach all tracked entities - {numCollection * 3:n0} tracked entities.")) { foreach (var entityEntry in context.ChangeTracker.Entries()) //#A { if (entityEntry.Entity != null) //#B { entityEntry.State = EntityState.Detached; //#C } } /******************************************** #A This will iterate through each tracked EntityEntry in the current DbContext instance #B This filters out tracked entities where the entity class instance has been set to null #C This sets the state of the EntityEntry to Detached **********************************************/ } //VERIFY var topEntity = context.Entry(entityToDetach); entityToDetach.Collection1.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); entityToDetach.Collection2.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); entityToDetach.Collection3.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); } }
public void TestThenIncludeWorksForMe() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var all = context.Employees .Include(x => x.WorksForMe) .ThenInclude(x => x.WorksForMe) .ToList(); //VERIFY all.Count.ShouldEqual(11); all.Count(x => x.Manager != null).ShouldEqual(10); all.Count(x => x.WorksForMe.Any()).ShouldEqual(5); var top = all.Single(x => x.Manager == null); top.ShowHierarchical(s => _output.WriteLine(s)); } }
public void TestLoadWorksForMeAsNoTrackingWithIdentityResolution() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using var context = new Chapter06Context(options); context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); context.ChangeTracker.Clear(); //ATTEMPT var all = context.Employees .AsNoTrackingWithIdentityResolution() .Include(x => x.WorksForMe) .ToList(); //VERIFY all.Count.ShouldEqual(11); all.Count(x => x.Manager != null).ShouldEqual(10); all.Count(x => x.WorksForMe.Any()).ShouldEqual(5); var top = all.Single(x => x.Manager == null); top.ShowHierarchical(s => _output.WriteLine(s)); }
public void TestDeletePrincipal() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using var context = new Chapter06Context(options); context.Database.EnsureCreated(); context.Add(new OnePrincipal { Link = new OneDependent() }); context.SaveChanges(); context.ChangeTracker.Clear(); //ATTEMPT var depToRemove = new OnePrincipal { Id = 1 }; context.Remove(depToRemove); context.SaveChanges(); //VERIFY context.OneDependents.Count().ShouldEqual(0); context.OnePrincipals.Count().ShouldEqual(0); }
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 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 TestAddTestEmployeesToDb() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using var context = new Chapter06Context(options); context.Database.EnsureCreated(); //ATTEMPT context.AddTestEmployeesToDb(); //VERIFY context.Employees.Count().ShouldEqual(11); }
public async Task TestBookQueryWithSeparateIncludesAsync() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); 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, "async load - first time")) { result = await context.ManyTops .AsSplitQuery() .Include(x => x.Collection1) .Include(x => x.Collection2) .Include(x => x.Collection3) .SingleAsync(); /********************************************************* #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, "async load - second time")) { result = await context.ManyTops .AsSplitQuery() .Include(x => x.Collection1) .Include(x => x.Collection2) .Include(x => x.Collection3) .SingleAsync(); } //VERIFY result.Collection1.Count.ShouldEqual(100); result.Collection2.Count.ShouldEqual(100); result.Collection3.Count.ShouldEqual(100); } }
public void TestLoadManager() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using var context = new Chapter06Context(options); context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); context.ChangeTracker.Clear(); //ATTEMPT var all = context.Employees.Include(x => x.Manager) .ToList(); //VERIFY all.Count.ShouldEqual(11); all.Count(x => x.Manager != null).ShouldEqual(10); all.Count(x => x.WorksForMe != null).ShouldEqual(5); all.Count(x => x.WorksForMe == null).ShouldEqual(6); }
public void TestDetachAllTrackedEntities(int numCollection) { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); var entityToDetach = context.AddManyTopWithRelationsToDb(); //ATTEMPT using (new TimeThings(_output, $"detach all tracked entities - {numCollection * 3:n0} tracked entities.")) { context.ChangeTracker.Clear(); } //VERIFY var topEntity = context.Entry(entityToDetach); entityToDetach.Collection1.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); entityToDetach.Collection2.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); entityToDetach.Collection3.All(x => context.Entry(x).State == EntityState.Detached).ShouldBeTrue(); } }
public void TestDetachViaCreatingNewDbContext(int numCollection) { //SETUP ManyTop entityToDetach; var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); entityToDetach = context.AddManyTopWithRelationsToDb(numCollection); } //ATTEMPT using (new TimeThings(_output, $"detach by creating new DbContext - {numCollection * 3:n0} tracked entities.")) { using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); } } //VERIFY }
public void TestBookQueryWithNormalIncludes() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); 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, "normal includes - first time")) { result = context.ManyTops .Include(x => x.Collection1) .Include(x => x.Collection2) .Include(x => x.Collection3) .Single(); } using (new TimeThings(_output, "normal includes - second time")) { result = context.ManyTops .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 TestCostOfNotDetaching(int numCollection) { //SETUP ManyTop entityToDetach; var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); //ATTEMPT using (new TimeThings(_output, "SaveChanges - no tracked entities.")) { context.SaveChanges(); } using (new TimeThings(_output, "SaveChanges - no tracked entities.")) { context.SaveChanges(); } entityToDetach = context.AddManyTopWithRelationsToDb(numCollection); var numEntities = entityToDetach.Collection1.Count + entityToDetach.Collection2.Count + entityToDetach.Collection3.Count; using (new TimeThings(_output, $"SaveChanges - {numEntities:n0} tracked entities.")) { context.SaveChanges(); } using (new TimeThings(_output, $"SaveChanges - {numEntities:n0} tracked entities.")) { context.SaveChanges(); } } //VERIFY }
public void ExampleDetachViaCreatingNewDbContext() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); options.StopNextDispose(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddManyTopWithRelationsToDb(); } //ATTEMPT ManyTop entityToDetach; //#A using (var tempContext = new Chapter06Context(options)) //#B { entityToDetach = tempContext.ManyTops.Single(); //#C var a = tempContext.Set <Many1>() //#D .Where(x => x.ManyTopId == entityToDetach.Id) //#D .ToList(); //#D //... rest of loads left out to shorten the example } //#E //… further code that uses the entityToDetach variable //#F /************************************************************************ #A This is the variable which will hold the detached entity class with its relationships that were read in separately #B Create a new instance of the application's DbContext. This must be done manually because you should not dispose of an instance that has been created by dependency injections #C Read of the top level entity class #D Read of the Many1 instances. Relational fixup will fill in the navigational collection in the ManyTop class which holds the loaded Many1 instances #E The closing of the using block means that the tempContext is disposed, including all ist tracking data #F As this point all the entity class instances read in while in the using block are detached from any DbContext * ********************************/ //VERIFY entityToDetach.Collection1.Count.ShouldEqual(100); }
public void TestMissingIncludeNotSafeOk() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using var context = new Chapter06Context(options); context.Database.EnsureCreated(); var bookSetup = new BookNotSafe(); bookSetup.Reviews.Add(new ReviewNotSafe()); context.Add(bookSetup); context.SaveChanges(); context.ChangeTracker.Clear(); //ATTEMPT var book = context.Books //#A //... missing Include(x => x.Reviews) //#B .First(x => x.Reviews.Any()); //VERIFY book.Reviews.ShouldNotBeNull(); }
public void TestLoadWorksForMeNoWorkingAsNoTracking() { //SETUP var options = SqliteInMemory.CreateOptions <Chapter06Context>(); using (var context = new Chapter06Context(options)) { context.Database.EnsureCreated(); context.AddTestEmployeesToDb(); } using (var context = new Chapter06Context(options)) { //ATTEMPT var all = context.Employees .AsNoTracking() .Include(x => x.WorksForMe) .ToList(); //VERIFY all.Count.ShouldEqual(11); all.Count(x => x.Manager == null).ShouldEqual(11); all.Count(x => x.WorksForMe.Any()).ShouldEqual(5); } }