Книги онлайн и без регистрации » Разная литература » Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 302 303 304 305 306 307 308 309 310 ... 407
Перейти на страницу:
добавляется в свойство DbSet<Make>, исполняющая среда EF Core автоматически начинает отслеживание также и дочерней записи Car без необходимости в ее явном добавлении в свойство DbSet<Car>. Выполнение метода SaveChanges() приводит к совместному сохранению Make и Car, что демонстрируется в следующем тесте:

[Fact]

public void ShouldAddAnObjectGraph()

{

  ExecuteInATransaction(RunTheTest);

  void RunTheTest()

  {

    var make = new Make {Name = "Honda"};

    var car = new Car { Color = "Yellow", MakeId = 1, PetName = "Herbie" };

    // Привести свойство Cars к List<Car> из IEnumerable<Car>.

    ((List<Car>)make.Cars).Add(car);

    Context.Makes.Add(make);

    var carCount = Context.Cars.Count();

    var makeCount = Context.Makes.Count();

    Context.SaveChanges();

    var newCarCount = Context.Cars. Count();

    var newMakeCount = Context.Makes. Count();

    Assert.Equal(carCount+1,newCarCount);

    Assert.Equal(makeCount+1,newMakeCount);

  }

}

Операторы добавления не пакетируются из-за наличия менее двух операторов, а в SQL Server пакетирование начинается с четырех операторов. Ниже показаны выполняемые операторы SQL:

exec sp_executesql N'SET NOCOUNT ON;

INSERT INTO [dbo].[Makes] ([Name])

VALUES (@p0);

SELECT [Id], [TimeStamp]

FROM [dbo].[Makes]

WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

',N'@p0 nvarchar(50)',@p0=N'Honda'

exec sp_executesql N'SET NOCOUNT ON;

INSERT INTO [dbo].[Inventory] ([Color], [MakeId], [PetName])

VALUES (@p1, @p2, @p3);

SELECT [Id], [IsDrivable], [TimeStamp]

FROM [dbo].[Inventory]

WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

',N'@p1 nvarchar(50),@p2 int,@p3 nvarchar(50)',@p1=N'Yellow',@p2=7,@p3=N'Herbie'

Обновление записей

Записи обновляются за счет их загрузки в DbSet<T> как отслеживаемой сущности, их изменения посредством кода и вызова метода SaveChanges() контекста. При выполнении SaveChanges() объект ChangeTracker сообщает обо всех модифицированных сущностях и исполняющая среда EF Core (наряду с поставщиком баз данных) создает надлежащий оператор SQL для обновления записи (или операторы SQL, если записей несколько).

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

Когда сущность редактируется, 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

Проверка параллелизма

Проверка параллелизма

1 ... 302 303 304 305 306 307 308 309 310 ... 407
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. В коментария нецензурная лексика и оскорбления ЗАПРЕЩЕНЫ! Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?