var newCarCount = Context.Cars.Count;

    Assert.Equal(carCount - 1, newCarCount);

    Assert.Equal(

      EntityState.Detached,

      Context.Entry(car).State);

  }

}

После вызова SaveChanges экземпляр сущности все еще существует, но больше не находится в ChangeTracker. Состоянием EntityState будет Detached. Вот как выглядит выполняемый код SQL:

exec sp_executesql N'SET NOCOUNT ON;

DELETE FROM [dbo].[Inventory]

WHERE [Id] = @p0 AND [TimeStamp] = @p1;

SELECT @@ROWCOUNT;'

,N'@p0 int,@p1 varbinary(8)',@p0=2,

@p1=0x0000000000008680

<p id="AutBody_Root1061"><strong>Удаление неотслеживаемых сущностей</strong></p>

Неотслеживаемые сущности способны удалять записи таким же способом, каким они могут обновлять записи. Удаление производится вызовом Remove/RemoveRange или установкой состояния в Deleted и последующим вызовом SaveChanges.

В показанном ниже тесте сначала читается запись как неотслеживаемая и на основе записи создается новый экземпляр класса Car. Затем либо устанавливается состояние в Deleted, либо применяется метод Remove класса DbSet (в зависимости от того, какая строка кода закомментирована) и вызывается SaveChanges. Все дополнительные контексты нужны для обеспечения точности теста и отсутствия пересечения между контекстами:

[Fact]

public void ShouldRemoveACarUsingState

{

  ExecuteInASharedTransaction(RunTheTest);

  void RunTheTest(IDbContextTransaction trans)

  {

    var carCount = Context.Cars.Count;

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

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

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

    context2.Entry(car).State = EntityState.Deleted;

    // context2.Cars.Remove(car);

    context2.SaveChanges;

    var newCarCount = Context.Cars.Count;

    Assert.Equal(carCount - 1, newCarCount);

    Assert.Equal(

      EntityState.Detached,

      Context.Entry(car).State);

  }

}

<p id="AutBody_Root1062"><strong>Перехват отказов каскадного удаления</strong></p>

Когда попытка удаления записи терпит неудачу из-за правил каскадирования, то исполняющая среда EFCore генерирует исключение DbUpdateException. Следующий тест демонстрирует это в действии:

[Fact]

public void ShouldFailToRemoveACar

{

  ExecuteInATransaction(RunTheTest);

   void RunTheTest

  {

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

    Context.Cars.Remove(car);

    Assert.Throws(

      =>Context.SaveChanges);

  }

}

<p id="AutBody_Root1063"><strong>Проверка параллелизма</strong></p>

Если сущность имеет свойство TimeStamp, то при удалении также используется проверка параллелизма. Дополнительную информацию ищите в подразделе "Проверка параллелизма" внутри раздела "Обновление записей" ранее в главе.

<p id="AutBody_Root1064"><strong>Резюме</strong></p>

В настоящей главе было закончено построение уровня доступа к данным AutoLot на основе сведений, полученных в предыдущей главе. С помощью инструментов командной строки EF Core вы создали шаблоны сущностей для существующей базы данных, обновили модель до финальной версии, а также создали и применили миграции. Для инкапсуляции доступа к данным вы добавили хранилища. Написанный код инициализации базы данных способен удалять и заново создавать базу данных повторяемым и надежным способом. В заключение готовый уровень доступа к данным главе был протестирован. На этом тема доступа к данным и Entity Framework Core завершена.

<p id="AutBody_Root1065"><strong>Часть VIII</strong></p><p><strong>Разработка клиентских приложений для Windows</strong></p><p id="AutBody_Root1066"><strong>Глава 24</strong></p><p><strong>Введение в Windows Presentation Foundation и XAML</strong></p>
Перейти на страницу:

Похожие книги