Основные операции с данными. CRUD

Последнее обновление: 30.01.2023

Большинство операций с данными так или иначе представляют собой 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);

Асинхронный API

Вместо метода 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}");
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850