public void Non_generic_reference_navigation_property_can_be_loaded_and_IsLoaded_is_set()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var driver = context.Drivers.Single(d => d.Name == "Jenson Button");
                var teamReference = context.Entry((object)driver).Reference("Team");

                Assert.False(teamReference.IsLoaded);
                teamReference.Load();
                Assert.True(teamReference.IsLoaded);
                Assert.Equal(Team.McLaren, driver.Team.Id);
            }
        }
        public void Generic_collection_navigation_property_can_be_loaded_and_IsLoaded_is_set()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                Assert.False(driversCollection.IsLoaded);
                driversCollection.Load();
                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);
            }
        }
        public void Related_collection_reload_after_detach_can_be_avoided_by_setting_IsLoaded_to_true()
        {
            using (var context = new F1Context())
            {
                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                Assert.Equal(3, team.Drivers.Count);
                Assert.True(driversCollection.IsLoaded);

                context.Entry(team.Drivers.First()).State = EntityState.Detached;

                Assert.False(driversCollection.IsLoaded);

                driversCollection.IsLoaded = true;
                Assert.Equal(2, team.Drivers.Count);
            }
        }
        private void TestDetectChanges(Action<F1Context> setupContext, Action<F1Context> actOnContext,
                                       bool autoDetectChanges, bool? expectDetectChanges = null)
        {
            using (var context = new F1Context())
            {
                context.Configuration.AutoDetectChangesEnabled = autoDetectChanges;

                setupContext(context);

                var mclaren = context.Teams.Find(Team.McLaren);
                var larryEntry = context.Entry(new Driver { Name = "Larry David" });
                mclaren.Drivers.Add(larryEntry.Entity);

                actOnContext(context);

                Assert.Equal(expectDetectChanges ?? autoDetectChanges ? EntityState.Added : EntityState.Detached,
                             larryEntry.State);
            }
        }
        public void Query_for_many_to_many_doesnt_work_well()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var sponsorsCollection = context.Entry(team).Collection(t => t.Sponsors);

                var query = sponsorsCollection.Query();
                query.Load();

                Assert.False(sponsorsCollection.IsLoaded);

                // This is due to a bug in CreateSourceQuery in core EF that cannot
                // be fixed in the productivity improvements.
                Assert.Equal(0, team.Sponsors.Count);
            }
        }
        public void Non_Generic_Query_for_collection_loads_related_end()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection("Drivers");

                var query = driversCollection.Query();
                query.Cast<Driver>().Where(d => d.Wins > 0).Load(); // Should only bring in two drivers

                Assert.False(driversCollection.IsLoaded);
                Assert.Equal(2, team.Drivers.Count);

                query.Load();

                Assert.False(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);
            }
        }
        private void DbPropertyEntry_method_can_be_used_on_previously_detached_entry_after_the_entity_becomes_tracked(
            Action<DbPropertyEntry> test)
        {
            using (var context = new F1Context())
            {
                var team = new Team
                           { Id = -1, Name = "Wubbsy Racing", Chassis = new Chassis { TeamId = -1, Name = "Wubbsy" } };
                var entry = context.Entry(team).Property(t => t.Name);

                context.Teams.Attach(team);

                test(entry); // Just testing here that this doesn't throw
            }
        }
        public void Setting_current_value_of_reference_nav_prop_to_null_for_an_independent_association_clears_the_relationship_even_if_it_is_not_loaded()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                Assert.Null(team.Engine);
                Assert.Equal(0, ((IObjectContextAdapter)context).ObjectContext
                                    .ObjectStateManager
                                    .GetObjectStateEntries(EntityState.Deleted)
                                    .Where(e => e.IsRelationship)
                                    .Count());

                context.Entry(team).Reference(p => p.Engine).CurrentValue = null;

                Assert.Null(team.Engine);
                Assert.Equal(1, ((IObjectContextAdapter)context).ObjectContext
                                    .ObjectStateManager
                                    .GetObjectStateEntries(EntityState.Deleted)
                                    .Where(e => e.IsRelationship)
                                    .Count());
            }
        }
        public void Collection_navigation_property_can_be_reloaded_even_if_marked_as_loaded()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                // Load drivers for the first time
                driversCollection.Load();

                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);

                // Add a new driver to the database
                using (var innerContext = new F1Context())
                {
                    innerContext.Drivers.Add(new Driver { Name = "Larry David", TeamId = Team.McLaren });
                    innerContext.SaveChanges();
                }

                // Now force load again
                Assert.True(driversCollection.IsLoaded);
                driversCollection.Load();

                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(4, team.Drivers.Count);
            }
        }
        public void RejectPropertyChanges_is_noop_for_a_property_that_is_not_modified()
        {
            using (var context = new F1Context())
            {
                var hamilton = context.Drivers.Where(d => d.Name == "Lewis Hamilton").Single();
                context.Entry(hamilton).Property(d => d.Podiums).CurrentValue = 1000;
                var stateEntry = GetObjectContext(context).ObjectStateManager.GetObjectStateEntry(hamilton);

                stateEntry.RejectPropertyChanges("Name");

                Assert.Equal(EntityState.Modified, stateEntry.State);
                Assert.Equal(1, stateEntry.GetModifiedProperties().Count());
                Assert.True(stateEntry.GetModifiedProperties().Contains("Podiums"));
            }
        }
        public void Collection_navigation_property_can_be_reloaded_with_AppendOnly_semantics()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                // Load drivers for the first time
                driversCollection.Load();

                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);

                // Now detach one driver from the collection and modify another one; the collection becomes unloaded
                context.Entry(context.Drivers.Local.Single(d => d.Name == "Jenson Button")).State = EntityState.Detached;
                context.Drivers.Local.Single(d => d.Name == "Lewis Hamilton").Wins = -1;

                // Check the collection has become unloaded because of the detach.  Reload it.
                Assert.False(driversCollection.IsLoaded);
                Assert.Equal(2, team.Drivers.Count);

                driversCollection.Load();

                // The detached driver should be back and the modified driver should not have been touched
                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);
                Assert.Equal(-1, context.Drivers.Local.Single(d => d.Name == "Lewis Hamilton").Wins);
            }
        }
        public void Setting_IsModified_to_false_for_a_modified_property_on_an_entity_which_also_has_a_conceptual_null_does_not_throw()
        {
            using (var context = new F1Context())
            {
                var hamilton = context.Drivers.Where(d => d.Name == "Lewis Hamilton").Include(d => d.Team).Single();
                hamilton.Team = null; // Creates conceptual null
                hamilton.Races++;
                var entry = context.Entry(hamilton);

                entry.Property(p => p.Races).IsModified = false; // Test that this doesn't throw

                Assert.True(entry.Property(p => p.TeamId).IsModified);
                Assert.Equal(EntityState.Modified, entry.State);

                // Conceptual null is still set so should throw now.
                Assert.Throws<InvalidOperationException>(() => GetObjectContext(context).AcceptAllChanges()).
                    ValidateMessage("ObjectContext_CommitWithConceptualNull");
            }
        }
        public void Reference_navigation_property_can_be_reloaded_with_AppendOnly_semantics()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var driver = context.Drivers.Single(d => d.Name == "Jenson Button");
                var teamReference = context.Entry(driver).Reference(d => d.Team);

                teamReference.Load();
                Assert.True(teamReference.IsLoaded);

                driver.Team.Principal = "Larry David";

                Assert.True(teamReference.IsLoaded);
                teamReference.Load();

                Assert.Equal("Larry David", driver.Team.Principal);
            }
        }
            Setting_IsModified_to_false_for_a_modified_property_which_is_a_conceptual_null_clears_that_conceptual_null()
        {
            using (var context = new F1Context())
            {
                var hamilton = context.Drivers.Where(d => d.Name == "Lewis Hamilton").Include(d => d.Team).Single();
                hamilton.Team = null; // Creates conceptual null
                var entry = context.Entry(hamilton);
                Assert.True(entry.Property(p => p.TeamId).IsModified);

                entry.Property(p => p.TeamId).IsModified = false;

                Assert.False(entry.Property(p => p.TeamId).IsModified);
                Assert.Equal(EntityState.Unchanged, entry.State);

                GetObjectContext(context).AcceptAllChanges(); // Will throw if there is a conceptual null
            }
        }
        public void Non_generic_collection_navigation_property_can_be_loaded_asynchronously_and_IsLoaded_is_set()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry((object)team).Collection("Drivers");

                Assert.False(driversCollection.IsLoaded);
                driversCollection.LoadAsync().Wait();
                Assert.True(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);
            }
        }
        public void Lazy_loading_no_longer_happens_after_setting_reference_to_null_for_FK_relationship()
        {
            using (var context = new F1Context())
            {
                var driver = context.Drivers.First();
                context.Entry(driver).Reference(p => p.Team).CurrentValue = null;

                Assert.Null(driver.Team); // Accessing the reference does not cause it to be loaded
            }
        }
        public void Lazy_loading_happens_after_setting_reference_to_null_for_FK_relationship_when_legacy_behavior_is_set_on_ObjectContext()
        {
            using (var context = new F1Context())
            {
                ((IObjectContextAdapter)context).ObjectContext.ContextOptions.UseConsistentNullReferenceBehavior = false;

                var driver = context.Drivers.First();
                context.Entry(driver).Reference(p => p.Team).CurrentValue = null;

                Assert.NotNull(driver.Team); // Reference is lazy loaded
            }
        }
        public void IsPropertyChanged_throws_for_a_deleted_entity()
        {
            using (var context = new F1Context())
            {
                var hamilton = context.Drivers.Where(d => d.Name == "Lewis Hamilton").Single();
                var stateEntry = GetObjectContext(context).ObjectStateManager.GetObjectStateEntry(hamilton);
                context.Entry(hamilton).State = EntityState.Deleted;

                Assert.Throws<InvalidOperationException>(() => stateEntry.IsPropertyChanged("Name")).ValidateMessage(
                    "ObjectStateEntry_SetModifiedStates");
            }
        }
        private void Current_collection_value_can_be_read_and_set(EntityState state)
        {
            using (var context = new F1Context())
            {
                var engineEntry = context.Entry(GetTeamEntry(context).Entity.Engine);
                engineEntry.State = state;
                var collectionEntry = engineEntry.Collection(t => t.Gearboxes);

                var value = collectionEntry.CurrentValue;
                Assert.Same(engineEntry.Entity.Gearboxes, value);

                value = new List<Gearbox>();
                collectionEntry.CurrentValue = value;
                Assert.Same(engineEntry.Entity.Gearboxes, value);
                context.ChangeTracker.DetectChanges();

                value = collectionEntry.CurrentValue;
                Assert.Same(engineEntry.Entity.Gearboxes, value);

                collectionEntry.CurrentValue = null;
                Assert.Null(collectionEntry.CurrentValue);
                context.ChangeTracker.DetectChanges();
            }
        }
        public void Reference_navigation_property_can_be_reloaded_after_changing_foreign_key()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var driver = context.Drivers.Single(d => d.Name == "Jenson Button");
                var teamReference = context.Entry(driver).Reference(d => d.Team);

                teamReference.Load();
                Assert.True(teamReference.IsLoaded);

                driver.TeamId = Team.Ferrari;

                Assert.True(teamReference.IsLoaded); // Because changes have not been detected yet

                teamReference = context.Entry(driver).Reference(d => d.Team); // Calls DetectChanges
                Assert.False(teamReference.IsLoaded);
                teamReference.Load();
                Assert.True(teamReference.IsLoaded);
                Assert.Equal(Team.Ferrari, driver.Team.Id);
            }
        }
        // Note that simple cases such as nulls that don't involve EF metadata are tested in the unit tests

        private DbEntityEntry<Team> GetTeamEntry(F1Context context)
        {
            var team = new Team
                       { Id = -1, Name = "Wubbsy Racing", Chassis = new Chassis { TeamId = -1, Name = "Wubbsy" } };
            team.Engine = new Engine
                          {
                              Id = -2,
                              Name = "WubbsyV8",
                              Teams = new List<Team> { team },
                              Gearboxes = new List<Gearbox>()
                          };
            context.Teams.Attach(team);
            return context.Entry(team);
        }
        private DbEntityEntry<Gearbox> GetGearboxEntry(F1Context context)
        {
            var team = GetTeamEntry(context).Entity;
            var gearbox = new Gearbox { Id = 1, Name = "WubbsyGears" };
            team.Gearbox = gearbox;
            team.Engine.Gearboxes.Add(gearbox);

            context.Entry(team).State = EntityState.Unchanged;

            return context.Entry(gearbox);
        }
        public void Non_Generic_Query_for_reference_loads_related_end()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var driver = context.Drivers.Single(d => d.Name == "Jenson Button");
                var teamReference = context.Entry(driver).Reference("Team");

                var query = teamReference.Query();
                query.Cast<Team>().Where(t => t.Id == Team.Ferrari).Load(); // Should not bring anything in

                Assert.False(teamReference.IsLoaded);

                query.Load();

                Assert.True(teamReference.IsLoaded);
                Assert.Equal(Team.McLaren, driver.Team.Id);
            }
        }
        private void Name_can_be_obtained_for_exposed_reference_nav_property_implementation(bool detached)
        {
            using (var context = new F1Context())
            {
                var teamEntry = context.Entry(new Team());
                if (!detached)
                {
                    teamEntry.State = EntityState.Added;
                }

                Assert.Equal("Chassis", teamEntry.Reference(t => t.Chassis).Name);
                Assert.Equal("Chassis", teamEntry.Reference("Chassis").Name);
                Assert.Equal("Chassis", teamEntry.Reference<Chassis>("Chassis").Name);
            }
        }
        public void Query_for_collection_can_be_used_to_count_without_loading_entities()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                var count = driversCollection.Query().Count();

                Assert.False(driversCollection.IsLoaded);
                Assert.Equal(0, team.Drivers.Count);
                Assert.Equal(3, count);
            }
        }
        private void Name_can_be_obtained_for_exposed_collection_nav_property_implementation(bool detached)
        {
            using (var context = new F1Context())
            {
                var teamEntry = context.Entry(new Team());
                if (!detached)
                {
                    teamEntry.State = EntityState.Added;
                }

                Assert.Equal("Drivers", teamEntry.Collection(t => t.Drivers).Name);
                Assert.Equal("Drivers", teamEntry.Collection("Drivers").Name);
                Assert.Equal("Drivers", teamEntry.Collection<Driver>("Drivers").Name);
            }
        }
        public void Collection_navigation_property_for_many_to_many_relationship_can_be_loaded()
        {
            using (var context = new F1Context())
            {
                context.Configuration.LazyLoadingEnabled = false;

                var team = context.Teams.Find(Team.McLaren);
                var sponsorsCollection = context.Entry(team).Collection(t => t.Sponsors);

                Assert.False(sponsorsCollection.IsLoaded);
                sponsorsCollection.Load();
                Assert.True(sponsorsCollection.IsLoaded);
                Assert.Equal(3, team.Sponsors.Count);
            }
        }
        private void Current_reference_value_for_one_to_one_principal_can_be_read_and_set(EntityState state)
        {
            using (var context = new F1Context())
            {
                var chassisEntry = context.Entry(GetTeamEntry(context).Entity.Chassis);
                chassisEntry.State = state;
                var refEntry = chassisEntry.Reference(c => c.Team);

                var value = refEntry.CurrentValue;
                Assert.Same(chassisEntry.Entity.Team, value);

                if (state == EntityState.Unchanged || state == EntityState.Modified)
                {
                    // Changing the reference to the principal will cause EF to throw a referential integrity exception
                    // because it would need a change in the PK of the dependent.
                    Assert.Throws<InvalidOperationException>(() => refEntry.CurrentValue = new Team()).ValidateMessage(
                        "EntityReference_CannotChangeReferentialConstraintProperty");
                }
                else
                {
                    value = new Team();
                    refEntry.CurrentValue = value;
                    Assert.Same(chassisEntry.Entity.Team, value);

                    if (state == EntityState.Deleted)
                    {
                        Assert.Throws<InvalidOperationException>(() => context.ChangeTracker.DetectChanges()).
                            ValidateMessage("RelatedEnd_UnableToAddRelationshipWithDeletedEntity");
                    }
                    else
                    {
                        context.ChangeTracker.DetectChanges();
                    }

                    value = refEntry.CurrentValue;
                    Assert.Same(chassisEntry.Entity.Team, value);
                }

                refEntry.CurrentValue = null;
                Assert.Null(refEntry.CurrentValue);
                Assert.Null(chassisEntry.Entity.Team);
                context.ChangeTracker.DetectChanges();
            }
        }
        private void TestDetectChangesWithSaveChanges(bool autoDetectChanges)
        {
            using (var context = new F1Context())
            {
                context.Database.Initialize(force: false);

                using (new TransactionScope())
                {
                    context.Configuration.AutoDetectChangesEnabled = autoDetectChanges;

                    var mclaren = context.Teams.Find(Team.McLaren);
                    var larryEntry = context.Entry(new Driver { Name = "Larry David" });
                    mclaren.Drivers.Add(larryEntry.Entity);

                    Assert.Equal(autoDetectChanges ? EntityState.Added : EntityState.Detached, larryEntry.State);

                    context.SaveChanges();

                    Assert.Equal(autoDetectChanges ? EntityState.Unchanged : EntityState.Detached, larryEntry.State);
                }
            }
        }
        public void Related_collection_IsLoaded_is_reset_when_one_of_the_related_entities_is_detached()
        {
            using (var context = new F1Context())
            {
                var team = context.Teams.Find(Team.McLaren);
                var driversCollection = context.Entry(team).Collection(t => t.Drivers);

                Assert.Equal(3, team.Drivers.Count);
                Assert.True(driversCollection.IsLoaded);

                var originalDriver = team.Drivers.OrderBy(d => d.Id).First();
                context.Entry(originalDriver).State = EntityState.Detached;

                Assert.False(driversCollection.IsLoaded);
                Assert.Equal(3, team.Drivers.Count);
                Assert.True(driversCollection.IsLoaded);

                var newDriver = team.Drivers.OrderBy(d => d.Id).First();
                Assert.Equal(originalDriver.Id, newDriver.Id);
                Assert.NotSame(originalDriver, newDriver);
            }
        }