Большинство операций с данными так или иначе представляют собой CRUD операции (Create, Read, Update, Delete), то есть создание, получение, обновление и удаление. Entity Framework Core позволяет легко выполнять все эти действия.
Для примера проект консольного приложения на C# и для работы с бд SQLite через Entity Framework добавим в него NuGet-пакет Microsoft.EntityFrameworkCore.Sqlite.
Затем добавим в проект класс User, объекты которого будут храниться в базе данных:
public class User { public int Id { get; set; } public string? Name { get; set; } public int Age { get; set; } }
И добавим класс контекста данных ApplicationContext:
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext() => Database.EnsureCreated(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite("Data Source=helloapp.db"); } }
Далее в файле Program.cs определим все базовые операции с данными:
// Добавление using (ApplicationContext db = new ApplicationContext()) { User tom = new User { Name = "Tom", Age = 33 }; User alice = new User { Name = "Alice", Age = 26 }; // Добавление db.Users.Add(tom); db.Users.Add(alice); db.SaveChanges(); } // получение using (ApplicationContext db = new ApplicationContext()) { // получаем объекты из бд и выводим на консоль var users = db.Users.ToList(); Console.WriteLine("Данные после добавления:"); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Редактирование using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User? user = db.Users.FirstOrDefault(); if (user != null) { user.Name = "Bob"; user.Age = 44; //обновляем объект //db.Users.Update(user); db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Удаление using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User? user = db.Users.FirstOrDefault(); if (user != null) { //удаляем объект db.Users.Remove(user); db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после удаления:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }
И после выполнения мы получим следующий консольный вывод:
Данные после добавления 1.Tom - 33 2.Alice - 26 Данные после редактирования 1.Bob - 44 2.Alice - 26 Данные после удаления 2.Alice - 26
Для добавления объекта используется метод Add, определенный у класса DbSet, в который передается добавляемый объект:
db.Users.Add(alice); db.SaveChanges();
Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Если нам надо добавить сразу несколько объектов, то мы можем воспользоваться методом AddRange():
User tom = new User { Name = "Tom", Age = 33 }; User alice = new User { Name = "Alice", Age = 26 }; db.Users.AddRange(tom, alice);
Удаление производится с помощью метода Remove:
db.Users.Remove(user); db.SaveChanges();
Данный метод установит статус объекта в Deleted, благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.
Если необходимо удалить сразу несколько объектов, то можно использовать метод RemoveRange():
User? firstUser = db.Users.FirstOrDefault(); User? secondUser = db.Users.FirstOrDefault(u=>u.Id==2); if (firstUser != null && secondUser != null) { db.Users.RemoveRange(firstUser, secondUser); db.SaveChanges(); }
При изменении объекта Entity Framework сам отслеживает все изменения, и когда вызывается метод SaveChanges(), будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.
Но надо отметить, что в данном случае действие контекста данных ограничивается пределами конструкции using, которая определяет область действия объекта ApplicationContext. Но рассмотрим другой пример. Мы получаем объект в одном месте,а обновляем в другом. Например:
User? user = null; using (ApplicationContext db = new ApplicationContext()) { // получаем объект user = db.Users.FirstOrDefault(); Console.WriteLine("Данные до редактирования:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } //................... // Редактирование using (ApplicationContext db = new ApplicationContext()) { // Редактирование if (user != null) { user.Name = "Sam"; user.Age = 33; db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (var u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }
Несмотря на то, что объект user не равен null, имеется в базе данных, но во втором блоке using обновления соответствующего объекта в БД не произойдет. Потому что объект User больше не отслеживается контекстом данных. И в этом случае во второй конструкции using, где происходит редактирование, нам надо использовать метод Update:
// Редактирование using (ApplicationContext db = new ApplicationContext()) { // Редактирование if (user != null) { user.Name = "Sam"; user.Age = 33; db.Users.Update(user); db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (var u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }
При необходимости обновить одновременно несколько объектов, применяется метод UpdateRange():
db.Users.UpdateRange(tom, alice);
Вместо метода SaveChanges() для асинхронного выполнения зароса к бд можно использовать его асинхронный двойник - SaveChangesAsync(). Также, для добавления данных определены асинхронные методы AddAsync и AddRangeAsync. Пример применения асинхронного API:
using Microsoft.EntityFrameworkCore; // для ToListAsync и FirstOrDefaultAsync // Добавление using (ApplicationContext db = new ApplicationContext()) { User tom = new User { Name = "Tom", Age = 33 }; User alice = new User { Name = "Alice", Age = 26 }; // Добавление await db.Users.AddRangeAsync(tom, alice); await db.SaveChangesAsync(); } // получение using (ApplicationContext db = new ApplicationContext()) { // получаем объекты из бд и выводим на консоль var users = await db.Users.ToListAsync(); Console.WriteLine("Данные после добавления:"); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Редактирование using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User? user = await db.Users.FirstOrDefaultAsync(); if (user != null) { user.Name = "Bob"; user.Age = 44; //обновляем объект await db.SaveChangesAsync(); } // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = await db.Users.ToListAsync(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Удаление using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User? user = await db.Users.FirstOrDefaultAsync(); if (user != null) { //удаляем объект db.Users.Remove(user); await db.SaveChangesAsync(); } // выводим данные после обновления Console.WriteLine("\nДанные после удаления:"); var users = await db.Users.ToListAsync(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }