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
, который устанавливает состояние в Modified
:
context2.Cars.Update(updatedCar);
Второй способ связан с применением экземпляра контекста и метода Entry()
для установки состояния в Modified
:
context2.Entry(updatedCar).State = EntityState.Modified;
В любом случае для сохранения значений все равно должен вызываться метод SaveChanges()
.
В представленном далее тесте читается неотслеживаемая запись, из нее создается новый экземпляр класса Car
и изменяется одно его свойство (Color
). Затем в зависимости от того, с какой строки кода вы уберете комментарий, либо устанавливается состояние, либо использует метод Update()
на DbSet
. Метод 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);