Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

Состояние сущности

Когда сущность редактируется,

EntityState
устанавливается в
Modified
. После успешного сохранения изменений состояние возвращается к
Unchanged
.

Обновление отслеживаемых сущностей

Обновление одиночной записи очень похоже на добавление одной записи. Вам понадобится загрузить запись из базы данных, внести в нее какие-то изменения и вызвать метод

SaveChanges
. Обратите внимание, что вам не нужно вызывать
Update/UpdateRange
на экземпляре
DbSet<T>
, поскольку сущности отслеживаются.
Представленный ниже тест обновляет только одну запись, но при обновлении и сохранении множества отслеживаемых сущностей процесс будет таким же:

[Fact]

public void ShouldUpdateACar

{

ExecuteInASharedTransaction(RunTheTest);

void RunTheTest(IDbContextTransaction trans)

{

var car = Context.Cars.First(c => c.Id == 1);

Assert.Equal("Black",car.Color);

car.Color = "White";

// Вызывать Update не нужно, т.к. сущность отслеживается.

// Context.Cars.Update(car);

Context.SaveChanges;

Assert.Equal("White", car.Color);

var context2 = TestHelpers.GetSecondContext(Context, trans);

var car2 = context2.Cars.First(c => c.Id == 1);

Assert.Equal("White", car2.Color);

}

}

В предыдущем коде задействована транзакция, совместно используемая двумя экземплярами

ApplicationDbContext
. Это должно обеспечить изоляцию между контекстом, выполняющим тест, и контекстом, проверяющим результат теста. Вот выполняемый оператор 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

На заметку! В показанной выше конструкции

WHERE
проверяется не только столбец
Id
, но и столбец
TimeStamp
. Проверка параллелизма будет раскрыта очень скоро .

Обновление неотслеживаемых сущностей

Неотслеживаемые сущности тоже можно использовать для обновления записей базы данных. Процесс аналогичен обновлению отслеживаемых сущностей за исключением того, что сущность создается в коде (и не запрашивается), а исполняющую среду EF Core потребуется уведомить о том, что сущность уже должна существовать в базе данных и нуждается в обновлении.

После создания экземпляра сущности есть два способа уведомления EF Core о том, что эту сущность необходимо обработать как обновление. Первый способ предусматривает вызов метода

Update
на экземпляре
DbSet<T>
, который устанавливает состояние в
Modified
:

context2.Cars.Update(updatedCar);

Второй способ связан с применением экземпляра контекста и метода

Entry
для установки состояния в
Modified
:

context2.Entry(updatedCar).State = EntityState.Modified;

В

любом случае для сохранения значений все равно должен вызываться метод
SaveChanges
.

В представленном далее тесте читается неотслеживаемая запись, из нее создается новый экземпляр класса

Car
и изменяется одно его свойство (
Color
). Затем в зависимости от того, с какой строки кода вы уберете комментарий, либо устанавливается состояние, либо использует метод
Update
на
DbSet<T>
. Метод
Update
также изменяет состояние на
Modified
. Затем в тесте вызывается метод
SaveChanges
. Все дополнительные контексты нужны для обеспечения точности теста и отсутствия пересечения между контекстами:

[Fact]

public void ShouldUpdateACarUsingState

{

ExecuteInASharedTransaction(RunTheTest);

void RunTheTest(IDbContextTransaction trans)

{

var car = Context.Cars.AsNoTracking.First(c => c.Id == 1);

Assert.Equal("Black", car.Color);

var updatedCar = new Car

{

Color = "White", //Original is Black

Id = car.Id,

MakeId = car.MakeId,

PetName = car.PetName,

TimeStamp = car.TimeStamp

IsDrivable = car.IsDrivable

};

var context2 = TestHelpers.GetSecondContext(Context, trans);

// Либо вызвать Update, либо модифицировать состояние.

context2.Entry(updatedCar).State = EntityState.Modified;

// context2.Cars.Update(updatedCar);

context2.SaveChanges;

var context3 =

TestHelpers.GetSecondContext(Context, trans);

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;

Поделиться с друзьями: