var car2 = context3.Cars.First(c => c.Id == 1);
Assert.Equal("White", car2.Color);
}
}
Ниже показан выполняющийся оператор SQL:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [dbo].[Inventory] SET [Color] = @p0
WHERE [Id] = @p1 AND [TimeStamp] = @p2;
SELECT [TimeStamp]
FROM [dbo].[Inventory]
WHERE @@ROWCOUNT = 1 AND [Id] = @p1;
',N'@p1 int,@p0 nvarchar(50),@p2 varbinary(8)',@p1=1,@p0=N'White',
@p2=0x000000000000862D
Проверка параллелизма
Проверка параллелизма подробно обсуждалась в предыдущей главе. Вспомните, что когда внутри сущности определено свойство TimeStamp
, то значение этого свойства используется в конструкции WHERE
при сохранении изменений (обновлений или удалений) в базе данных. Вместо поиска только первичного ключа к запросу добавляется поиск значения TimeStamp
, например:
UPDATE [dbo].[Inventory] SET [PetName] = @p0
WHERE [Id] = @p1 AND [TimeStamp] = @p2;
В следующем тесте демонстрируется пример создания исключения, связанного с параллелизмом, его перехвата и применения Entries
для получения исходных значений, текущих значений и значений, которые в настоящий момент хранятся в базе данных. Получение текущих значений требует еще одного обращения к базе данных:
[Fact]
public void ShouldThrowConcurrencyException()
{
ExecuteInATransaction(RunTheTest);
void RunTheTest()
{
var car = Context.Cars.First();
// Обновить базу данных за пределами контекста.
Context.Database.ExecuteSqlInterpolated(
$"Update dbo.Inventory set Color='Pink' where Id = {car.Id}");
car.Color = "Yellow";
var ex = Assert.Throws
() => Context.SaveChanges());
var entry = ((DbUpdateConcurrencyException) ex.InnerException)?.Entries[0];
PropertyValues originalProps = entry.OriginalValues;
PropertyValues currentProps = entry.CurrentValues;
// Требует еще одного обращения к базе данных.
PropertyValues databaseProps = entry.GetDatabaseValues();
}
}
Ниже показаны выполняемые операторы SQL. Первым из них является оператор UPDATE, а вторым — обращение для получения значений базы данных:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [dbo].[Inventory] SET [Color] = @p0
WHERE [Id] = @p1 AND [TimeStamp] = @p2;
SELECT [TimeStamp]
FROM [dbo].[Inventory]
WHERE @@ROWCOUNT = 1 AND [Id] = @p1;'
,N'@p1 int,@p0 nvarchar(50),@p2 varbinary(8)',@p1=1,@p0=N'Yellow',
@p2=0x0000000000008665
exec sp_executesql N'SELECT TOP(1) [i].[Id], [i].[Color],
[i].[IsDrivable], [i].[MakeId],
[i].[PetName], [i].[TimeStamp]
FROM [dbo].[Inventory] AS [i]
WHERE [i].[Id] = @__p_0',N'@__p_0 int',@__p_0=1
Удаление записей
Одиночная сущность помечается для удаления путем вызова Remove()
на DbSet
или установки ее состояния в Deleted
. Список записей помечается для удаления вызовом RemoveRange()
на DbSet
. Процесс удаления будет вызывать эффекты каскадирования для навигационных свойств на основе правил, сконфигурированных в методе OnModelCreating()
(и регламентированных соглашениями EF Core). Если удаление не допускается из -за политики каскадирования, тогда генерируется исключение.
Состояние сущности