public static async Task FirstOrNotFoundAsync_EntityDoesNotExist_ThrowNotFoundException(TestDbContext dbContext)
 {
     try
     {
         var order = await dbContext.SettlementOrders
                     .Include(o => o.IndividualConsumers)
                     .Include(o => o.OrganisationalConsumers)
                     .FirstOrNotFoundAsync(o => o.Id == 999999, nameof(SettlementOrder), 999999, CancellationToken.None);
     }
     catch (NotFoundException)
     {
         ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityDoesNotExist_ThrowNotFoundException), true);
     }
     catch (Exception)
     {
         ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityDoesNotExist_ThrowNotFoundException), false);
     }
 }
        public static async Task FirstOrDefaultAsync_EntityDoesNotExist_ReturnDefault(TestDbContext dbContext)
        {
            try
            {
                var order = await dbContext.SettlementOrders
                            .Include(o => o.IndividualConsumers)
                            .Include(o => o.OrganisationalConsumers)
                            .FirstOrDefaultAsync(o => o.Id == 999999);

                if (order == default)
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrDefaultAsync_EntityDoesNotExist_ReturnDefault), true);
                }
            }
            catch (Exception)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityDoesNotExist_ThrowNotFoundException), false);
            }
        }
        public static async Task NavigationProperty_EntityNotIncluded_ThrowException(TestDbContext dbContext)
        {
            try
            {
                var order = await dbContext.SettlementOrders
                            .FirstOrNotFoundAsync(o => o.Id == 1, nameof(SettlementOrder), 1, CancellationToken.None);

                var consumersCount = order.IndividualConsumers.Count;

                if (consumersCount >= 0)
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(NavigationProperty_EntityNotIncluded_ThrowException), false);
                }
            }
            catch (Exception)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(NavigationProperty_EntityNotIncluded_ThrowException), true);
            }
        }
        public static async Task FirstOrNotFoundAsync_EntityExists_ReturnEntity(TestDbContext dbContext)
        {
            try
            {
                var order = await dbContext.SettlementOrders
                            .Include(o => o.IndividualConsumers)
                            .Include(o => o.OrganisationalConsumers)
                            .FirstOrNotFoundAsync(o => o.Id == 1, nameof(SettlementOrder), 1, CancellationToken.None);

                if (order != null)
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityExists_ReturnEntity), true);
                }
                else
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityExists_ReturnEntity), false);
                }
            }
            catch (Exception)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(FirstOrNotFoundAsync_EntityExists_ReturnEntity), false);
            }
        }
        public static async Task OwnedEntity_OwningEntityExists_NoExceptionThrown(TestDbContext dbContext)
        {
            try
            {
                var order = await dbContext.SettlementOrders
                            .FirstOrNotFoundAsync(o => o.Id == 1, nameof(SettlementOrder), 1, CancellationToken.None);

                var address = order.ForwardingAddress;

                if (address.State == null)
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(OwnedEntity_OwningEntityExists_NoExceptionThrown), false);
                }
                else
                {
                    ConsoleLoggingHelper.WriteTestResult(nameof(OwnedEntity_OwningEntityExists_NoExceptionThrown), true);
                }
            }
            catch (Exception)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(OwnedEntity_OwningEntityExists_NoExceptionThrown), false);
            }
        }
        private static async Task EfCoreDemo_RestrictedClientEvaluation(ITestDbContext dbContext)
        {
            var expectedExceptionThrown   = false;
            var unexpectedExceptionThrown = false;

            try
            {
                // This will fail because EF can't translate 'HasCorrectIdentifierForDemo(o.Identifier)' into SQL.
                var result = await dbContext.SettlementOrders.AsNoTracking()
                             .Where(o => o.Identifier.Contains("EF") && HasCorrectIdentifierForDemo(o.Identifier))
                             .Select(o => o.Id)
                             .ToListAsync();
            }
            catch (InvalidOperationException translationFailedException)
            {
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine("----------------------------------------");
                Console.WriteLine("-- EfCoreDemo_RestrictedClientEvaluation");
                Console.WriteLine();
                Console.WriteLine(translationFailedException.Message);
                Console.WriteLine();

                expectedExceptionThrown = true;
            }

            // If we really need to get this to evaluate on the Client side, then we need to instruct EF to bring
            // the records into memory for further processing, like so:

            // ----------------------------------------
            // -- Synchronously

            try
            {
                var results = dbContext.SettlementOrders.AsNoTracking()
                              .Where(o => o.Identifier.Contains("Ef"))               // <-- Processed on the Server (SQL) - i.e. Translates to SQL
                              .AsEnumerable()                                        // <-- This will force the records to load into memory after the SQL component is finished.
                              .Where(o => HasCorrectIdentifierForDemo(o.Identifier)) // <-- Processed Client Side (C#)
                              .Select(o => o.Id)
                              .ToList();                                             // Yes, this is NOT Async. And that's by design.

                if (results.Count != 1)
                {
                    throw new Exception("Invalid Data - EfCoreDemo_RestrictedClientEvaluation");
                }
            }
            catch (Exception)
            {
                unexpectedExceptionThrown = true;
            }

            // ----------------------------------------
            // -- Asynchronously

            try
            {
                var results     = new List <int>();
                var ordersQuery = dbContext.SettlementOrders.AsNoTracking()
                                  .Where(o => o.Identifier.Contains("Ef")); // <-- Processed on the Server (SQL) - i.e. Translates to SQL

                await foreach (var order in ordersQuery.AsAsyncEnumerable())
                {
                    if (HasCorrectIdentifierForDemo(order.Identifier))
                    {
                        results.Add(order.Id);
                    }
                }

                if (results.Count != 1)
                {
                    throw new Exception("Invalid Data - EfCoreDemo_RestrictedClientEvaluation");
                }
            }
            catch (Exception)
            {
                unexpectedExceptionThrown = true;
            }

            if (unexpectedExceptionThrown || !expectedExceptionThrown)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(EfCoreDemo_RestrictedClientEvaluation), passed: false);
            }
            else
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(EfCoreDemo_RestrictedClientEvaluation), passed: true);
            }
        }
        private static async Task EfCoreDemo_ReferenceStitchingChanges(IServiceProvider serviceProvider)
        {
            var expectedExceptionThrown   = false;
            var unexpectedExceptionThrown = false;

            // ----------------------------------------
            // -- Incorrect Method

            try
            {
                using var scope     = serviceProvider.CreateScope();
                using var dbContext = scope.ServiceProvider.GetRequiredService <ITestDbContext>();

                var order    = new SettlementOrder();
                var document = new Document
                {
                    OrderId  = order.Id,
                    FilePath = "EfCoreDemo_ReferenceStitchingChanges_Incorrect"
                };

                dbContext.Documents.Add(document);
                dbContext.SettlementOrders.Add(order);

                await dbContext.SaveChangesAsync(CancellationToken.None);
            }
            catch (Exception)
            {
                expectedExceptionThrown = true;
            }

            // ----------------------------------------
            // -- Correct Method

            try
            {
                using var scope     = serviceProvider.CreateScope();
                using var dbContext = scope.ServiceProvider.GetRequiredService <ITestDbContext>();

                var order    = new SettlementOrder();
                var document = new Document
                {
                    Order    = order,
                    FilePath = "EfCoreDemo_ReferenceStitchingChanges_Success"
                };

                dbContext.Documents.Add(document);
                dbContext.SettlementOrders.Add(order);

                await dbContext.SaveChangesAsync(CancellationToken.None);
            }
            catch (Exception)
            {
                unexpectedExceptionThrown = true;
            }

            if (unexpectedExceptionThrown || !expectedExceptionThrown)
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(EfCoreDemo_ReferenceStitchingChanges), passed: false);
            }
            else
            {
                ConsoleLoggingHelper.WriteTestResult(nameof(EfCoreDemo_ReferenceStitchingChanges), passed: true);
            }
        }