public async Task BatchCommands_creates_valid_batch_for_added_entities()
        {
            var stateEntry = new MixedStateEntry(
                CreateConfiguration(),
                CreateSimpleFKModel().GetEntityType(typeof(FakeEntity)), new FakeEntity { Id = 42, Value = "Test" });

            await stateEntry.SetEntityStateAsync(EntityState.Added);

            var commandBatches = CreateCommandBatchPreparer().BatchCommands(new[] { stateEntry }).ToArray();
            Assert.Equal(1, commandBatches.Count());
            Assert.Equal(1, commandBatches.First().ModificationCommands.Count());

            var command = commandBatches.First().ModificationCommands.Single();
            Assert.Equal(EntityState.Added, command.EntityState);
            Assert.Equal(2, command.ColumnModifications.Count);

            var columnMod = command.ColumnModifications[0];

            Assert.Equal("Id", columnMod.ColumnName);
            Assert.Same(stateEntry, columnMod.StateEntry);
            Assert.Equal("Id", columnMod.Property.Name);
            Assert.False(columnMod.IsCondition);
            Assert.True(columnMod.IsKey);
            Assert.False(columnMod.IsRead);
            Assert.True(columnMod.IsWrite);

            columnMod = command.ColumnModifications[1];

            Assert.Equal("Value", columnMod.ColumnName);
            Assert.Same(stateEntry, columnMod.StateEntry);
            Assert.Equal("Value", columnMod.Property.Name);
            Assert.False(columnMod.IsCondition);
            Assert.False(columnMod.IsKey);
            Assert.False(columnMod.IsRead);
            Assert.True(columnMod.IsWrite);
        }
        public async Task BatchCommands_creates_batches_lazily()
        {
            var configuration = CreateConfiguration();
            var model = CreateSimpleFKModel();

            var fakeEntity = new FakeEntity { Id = 42, Value = "Test" };
            var stateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(FakeEntity)), fakeEntity);
            await stateEntry.SetEntityStateAsync(EntityState.Added);

            var relatedStateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(RelatedFakeEntity)), new RelatedFakeEntity { Id = 42 });
            await relatedStateEntry.SetEntityStateAsync(EntityState.Added);

            var modificationCommandBatchFactoryMock = new Mock<ModificationCommandBatchFactory>();

            var commandBatches = CreateCommandBatchPreparer(modificationCommandBatchFactoryMock.Object).BatchCommands(new[] { relatedStateEntry, stateEntry });

            var commandBatchesEnumerator = commandBatches.GetEnumerator();
            commandBatchesEnumerator.MoveNext();

            modificationCommandBatchFactoryMock.Verify(mcb => mcb.Create(), Times.Once);

            commandBatchesEnumerator.MoveNext();

            modificationCommandBatchFactoryMock.Verify(mcb => mcb.Create(), Times.Exactly(2));
        }
        public async Task BatchCommands_sorts_unrelated_entities()
        {
            var configuration = CreateConfiguration();
            var model = CreateSimpleFKModel();

            var firstStateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(FakeEntity)), new FakeEntity { Id = 42, Value = "Test" });
            await firstStateEntry.SetEntityStateAsync(EntityState.Added);

            var secondStateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(RelatedFakeEntity)), new RelatedFakeEntity { Id = 1 });
            await secondStateEntry.SetEntityStateAsync(EntityState.Added);

            var commandBatches = CreateCommandBatchPreparer().BatchCommands(new[] { secondStateEntry, firstStateEntry }).ToArray();

            Assert.Equal(
                new[] { firstStateEntry, secondStateEntry },
                commandBatches.Select(cb => cb.ModificationCommands.Single()).Select(mc => mc.StateEntries.Single()));
        }
        public async Task BatchCommands_sorts_entities_when_reparenting()
        {
            var configuration = CreateConfiguration();
            var model = CreateCyclicFKModel();

            var previousParent = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(FakeEntity)), new FakeEntity { Id = 42, Value = "Test" });
            await previousParent.SetEntityStateAsync(EntityState.Deleted);

            var newParent = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(FakeEntity)), new FakeEntity { Id = 3, Value = "Test" });
            await newParent.SetEntityStateAsync(EntityState.Added);

            var relatedStateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(RelatedFakeEntity)), new RelatedFakeEntity { Id = 1, RelatedId = 3 });
            await relatedStateEntry.SetEntityStateAsync(EntityState.Modified);
            relatedStateEntry.OriginalValues[relatedStateEntry.EntityType.GetProperty("RelatedId")] = 42;
            relatedStateEntry.SetPropertyModified(relatedStateEntry.EntityType.GetKey().Properties.Single(), isModified: false);

            var commandBatches = CreateCommandBatchPreparer().BatchCommands(new[] { relatedStateEntry, previousParent, newParent }).ToArray();

            Assert.Equal(
                new[] { newParent, relatedStateEntry, previousParent },
                commandBatches.Select(cb => cb.ModificationCommands.Single()).Select(mc => mc.StateEntries.Single()));
        }
        public async Task BatchCommands_throws_on_modified_principal_key()
        {
            var configuration = CreateConfiguration();
            var model = CreateSimpleFKModel();

            var stateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(FakeEntity)), new FakeEntity { Id = 42, Value = "Test" });
            await stateEntry.SetEntityStateAsync(EntityState.Modified);
            stateEntry.SetPropertyModified(stateEntry.EntityType.GetKey().Properties.Single(), isModified: true);

            var relatedStateEntry = new MixedStateEntry(
                configuration,
                model.GetEntityType(typeof(RelatedFakeEntity)), new RelatedFakeEntity { Id = 42 });
            await relatedStateEntry.SetEntityStateAsync(EntityState.Modified);

            Assert.Equal(
                Strings.FormatPrincipalKeyModified(),
                Assert.Throws<InvalidOperationException>(() => CreateCommandBatchPreparer().BatchCommands(new[] { relatedStateEntry, stateEntry })).Message);
        }