Язык программирования C#9 и платформа .NET5
[InlineData(4, "Clunker")][InlineData(5, "Bimmer")][InlineData(6, "Hank")][InlineData(7, "Pinky")][InlineData(8, "Pete")][InlineData(9, "Brownie")]public void ShouldGetValueFromStoredProc(int id, string expectedName){Assert.Equal(expectedName, new CarRepo(Context).GetPetName(id));}Создание записей
Записи добавляются в базу данных за счет их создания в коде, добавления к
и вызова методаDbSet<T>контекста. Во время выполнения методаSaveChanges()/SaveChangesAsync()объектSaveChanges()сообщает обо всех добавленных сущностях, а инфраструктура EF Core вместе с поставщиком баз данных создают подходящий оператор (операторы) SQL для вставки записи (записей).ChangeTrackerВспомните, что метод
выполняется в неявной транзакции, если только не применяется явная транзакция. Если сохранение было успешным, то затем запрашиваются значения, сгенерированные сервером, для установки значений в сущностях. Все эти тесты будут использовать явную транзакцию, так что можно производить откат, оставив базу данных в том же состоянии, в каком она находилась, когда начинался прогон тестов.SaveChanges()Все операторы SQL, показанные далее в разделе, были получены с применением профилировщика SQL Server.
На заметку! Записи можно добавлять также с использованием класса, производного от
. Во всех примерах для добавления записей будут применяться свойстваDbContext. В классахDbSet<T>иDbSet<T>имеются асинхронные версии методовDbContext, но здесь рассматриваются только синхронные версии.Add()/AddRange()Состояние сущности
Когда сущность создана с помощью кода, но еще не была добавлена в
, значениемDbSet<T>являетсяEntityState. После добавления новой сущности вDetachedзначениеDbSet<T>устанавливается вEntityState. В случае успешного выполненияAddedзначениеSaveChanges()устанавливается вEntityState.UnchangedДобавление одной записи
В следующем тесте демонстрируется добавление одиночной записи в таблицу
:Inventory[Fact]public void ShouldAddACar(){ExecuteInATransaction(RunTheTest);void RunTheTest(){var car = new Car{Color = "Yellow",MakeId = 1,PetName = "Herbie"};var carCount = Context.Cars.Count();Context.Cars.Add(car);Context.SaveChanges();var newCarCount = Context.Cars.Count();Assert.Equal(carCount+1,newCarCount);}}Ниже приведен выполняемый оператор SQL. Обратите внимание, что у недавно добавленной сущности запрашиваются свойства, сгенерированные базой данных (
иId). Когда результат запроса поступает в исполняющую среду EF Core, сущность обновляется с использованием значений серверной стороны:TimeStampexec sp_executesql N'SET NOCOUNT ON;INSERT INTO [dbo].[Inventory] ([Color], [MakeId], [PetName])VALUES (@p0, @p1, @p2);SELECT [Id], [IsDrivable], [TimeStamp]FROM [dbo].[Inventory]WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();',N'@p0 nvarchar(50),@p1 int,@p2 nvarchar(50)',@p0=N'Yellow',@p1=1,@p2=N'Herbie'Добавление одной записи с использованием метода Attach()
Когда первичный ключ сущности сопоставлен со столбцом идентичности в SQL Server, исполняющая среда EF Core будет трактовать экземпляр сущности как добавленный (
), если значение свойства первичного ключа равно 0. Следующий тест создает новую сущностьAddedи оставляет для свойстваCarстандартное значение 0. После присоединения сущности кIdее состояние устанавливается вChangeTrackerи вызовAddedдобавит сущность в базу данных:SaveChanges()[Fact]public void ShouldAddACarWithAttach(){ExecuteInATransaction(RunTheTest);void RunTheTest(){var car = new Car{Color = "Yellow",MakeId = 1,PetName = "Herbie"};var carCount = Context.Cars.Count();Context.Cars.Attach(car);Assert.Equal(EntityState.Added, Context.Entry(car).State);