Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом пошаговом руководстве показано, как создать простое приложение Windows Forms (WinForms), поддерживаемое базой данных SQLite. Приложение использует Entity Framework Core (EF Core) для загрузки данных из базы данных, отслеживания изменений, внесенных в эти данные, и сохранения этих изменений обратно в базу данных.
Снимки экрана и описания кода в этом пошаговом руководстве взяты из Visual Studio 2022 17.3.0.
Совет
Вы можете скачать используемый в этой статье пример из репозитория GitHub.
Необходимые компоненты
Для выполнения этого пошагового руководства необходимо установить Visual Studio 2022 17.3 или более поздней версии с рабочей нагрузкой рабочего стола .NET. Дополнительные сведения об установке новейшей версии Visual Studio см. в статье Установка Visual Studio.
Создание приложения
Запустите Visual Studio
На начальном экране выберите Создать проект.
Выберите приложение Windows Forms и нажмите кнопку "Далее".
На следующем экране укажите имя проекта, например GetStartedWinForms и нажмите кнопку "Далее".
На следующем экране выберите используемую версию .NET. Это пошаговое руководство было создано с помощью .NET 7, но оно также должно работать с более поздними версиями.
Выберите Создать.
Установка пакетов NuGet EF Core
Щелкните правой кнопкой мыши решение и выберите Управление пакетами NuGet для решения...
Перейдите на вкладку "Обзор" и найдите "Microsoft.EntityFrameworkCore.Sqlite".
Выберите пакет Microsoft.EntityFrameworkCore.Sqlite.
Проверьте проект GetStartedWinForms в правой области.
Выберите последнюю версию. Чтобы использовать предварительную версию, установите флажок "Включить предварительную версию".
Щелкните Установить.
Примечание.
Microsoft.EntityFrameworkCore.Sqlite — это пакет поставщика базы данных для использования EF Core с базой данных SQLite. Аналогичные пакеты доступны для других систем баз данных. Установка пакета поставщика базы данных автоматически приводит все зависимости, необходимые для использования EF Core с этой системой базы данных. Сюда входит базовый пакет Microsoft.EntityFrameworkCore .
Определение модели
В этом пошаговом руководстве мы реализуем модель с помощью Code First. Таким образом, EF Core создаст таблицы и схему базы данных на основе определенных вами классов C#. См. статью "Управление схемами баз данных" , чтобы узнать, как использовать существующую базу данных.
Щелкните проект правой кнопкой мыши и нажмите кнопку "Добавить", а затем "Класс" , чтобы добавить новый класс.
Используйте имя
Product.csфайла и замените код для класса следующим образом:using System.ComponentModel; namespace GetStartedWinForms; public class Product { public int ProductId { get; set; } public string? Name { get; set; } public int CategoryId { get; set; } public virtual Category Category { get; set; } = null!; }Повторите создание
Category.csс помощью следующего кода:using Microsoft.EntityFrameworkCore.ChangeTracking; namespace GetStartedWinForms; public class Category { public int CategoryId { get; set; } public string? Name { get; set; } public virtual ObservableCollectionListSource<Product> Products { get; } = new(); }
Свойство ProductsCategory класса и Category свойства класса Product называются навигациями. В EF Core навигации определяют связь между двумя типами сущностей. В этом случае навигация Product.Category ссылается на категорию, к которой принадлежит данный продукт. Аналогичным образом навигация Category.Products по коллекции содержит все продукты для данной категории.
Совет
При использовании Windows Forms , ObservableCollectionListSourceкоторый реализует IListSource, можно использовать для навигации по коллекции. Это не обязательно, но улучшает двусторонняя привязка данных.
Определение DbContext
В EF Core класс, производный от DbContext этого, используется для настройки типов сущностей в модели и выступает в качестве сеанса для взаимодействия с базой данных. В самом простом случае DbContext класс:
- Содержит
DbSetсвойства для каждого типа сущности в модели. - Переопределяет
OnConfiguringметод для настройки поставщика базы данных и строка подключения для использования. Дополнительные сведения см. в разделе "Настройка DbContext ".
В этом случае класс DbContext также переопределяет OnModelCreating метод для предоставления некоторых примеров данных для приложения.
Добавьте новый ProductsContext.cs класс в проект со следующим кодом:
using Microsoft.EntityFrameworkCore;
namespace GetStartedWinForms;
public class ProductsContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=products.db");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category { CategoryId = 1, Name = "Cheese" },
new Category { CategoryId = 2, Name = "Meat" },
new Category { CategoryId = 3, Name = "Fish" },
new Category { CategoryId = 4, Name = "Bread" });
modelBuilder.Entity<Product>().HasData(
new Product { ProductId = 1, CategoryId = 1, Name = "Cheddar" },
new Product { ProductId = 2, CategoryId = 1, Name = "Brie" },
new Product { ProductId = 3, CategoryId = 1, Name = "Stilton" },
new Product { ProductId = 4, CategoryId = 1, Name = "Cheshire" },
new Product { ProductId = 5, CategoryId = 1, Name = "Swiss" },
new Product { ProductId = 6, CategoryId = 1, Name = "Gruyere" },
new Product { ProductId = 7, CategoryId = 1, Name = "Colby" },
new Product { ProductId = 8, CategoryId = 1, Name = "Mozzela" },
new Product { ProductId = 9, CategoryId = 1, Name = "Ricotta" },
new Product { ProductId = 10, CategoryId = 1, Name = "Parmesan" },
new Product { ProductId = 11, CategoryId = 2, Name = "Ham" },
new Product { ProductId = 12, CategoryId = 2, Name = "Beef" },
new Product { ProductId = 13, CategoryId = 2, Name = "Chicken" },
new Product { ProductId = 14, CategoryId = 2, Name = "Turkey" },
new Product { ProductId = 15, CategoryId = 2, Name = "Prosciutto" },
new Product { ProductId = 16, CategoryId = 2, Name = "Bacon" },
new Product { ProductId = 17, CategoryId = 2, Name = "Mutton" },
new Product { ProductId = 18, CategoryId = 2, Name = "Pastrami" },
new Product { ProductId = 19, CategoryId = 2, Name = "Hazlet" },
new Product { ProductId = 20, CategoryId = 2, Name = "Salami" },
new Product { ProductId = 21, CategoryId = 3, Name = "Salmon" },
new Product { ProductId = 22, CategoryId = 3, Name = "Tuna" },
new Product { ProductId = 23, CategoryId = 3, Name = "Mackerel" },
new Product { ProductId = 24, CategoryId = 4, Name = "Rye" },
new Product { ProductId = 25, CategoryId = 4, Name = "Wheat" },
new Product { ProductId = 26, CategoryId = 4, Name = "Brioche" },
new Product { ProductId = 27, CategoryId = 4, Name = "Naan" },
new Product { ProductId = 28, CategoryId = 4, Name = "Focaccia" },
new Product { ProductId = 29, CategoryId = 4, Name = "Malted" },
new Product { ProductId = 30, CategoryId = 4, Name = "Sourdough" },
new Product { ProductId = 31, CategoryId = 4, Name = "Corn" },
new Product { ProductId = 32, CategoryId = 4, Name = "White" },
new Product { ProductId = 33, CategoryId = 4, Name = "Soda" });
}
}
Обязательно создайте решение на этом этапе.
Добавление элементов управления на форму
Приложение отобразит список категорий и список продуктов. Если в первом списке выбрана категория, то второй список изменится, чтобы отобразить продукты для этой категории. Эти списки можно изменить, чтобы добавить, удалить или изменить продукты и категории, и эти изменения можно сохранить в базе данных SQLite, нажав кнопку "Сохранить ".
Измените имя основной формы на
Form1MainForm.
И измените заголовок на "Продукты и категории".
С помощью панели элементов добавьте два
DataGridViewэлемента управления, расположенные рядом друг с другом.
В свойствах для первого
DataGridViewизмените имяdataGridViewCategoriesна .В свойствах второго
DataGridViewизмените имяdataGridViewProductsна .Кроме того, с помощью панели элементов добавьте
Buttonэлемент управления.Назовите кнопку
buttonSaveи присвойте ей текст "Сохранить". Форма должна выглядеть следующим образом:
Привязка данных
Следующим шагом является подключение Product и Category типы из модели к DataGridView элементам управления. Это привязывает данные, загруженные EF Core, к элементам управления, таким образом, что сущности, отслеживаемые EF Core, синхронизируются с данными, отображаемыми в элементах управления.
Щелкните глиф действия конструктора на первом
DataGridView. Это крошечная кнопка в правом верхнем углу элемента управления.
Откроется список действий, из которого можно получить доступ к раскрывающемся списку для выбранного источника данных. Мы еще не создали источник данных, поэтому перейдите к нижнему краю и нажмите кнопку "Добавить новый источник данных объекта...".
Выберите категорию , чтобы создать источник данных объекта для категорий и нажмите кнопку "ОК".
Совет
Если здесь нет типов источников данных, убедитесь, что
Product.csон добавлен в проектCategory.cs.ProductsContext.csТеперь раскрывающийся список "Выбор источника данных" содержит только что созданный источник данных объекта. Разверните другие источники данных, а затем выберите "Источники данных проекта" и выберите категорию.
Второй
DataGridViewбудет привязан к продуктам. Однако вместо привязки к типу верхнего уровняProductона будет привязана кProductsнавигации изCategoryпривязки первойDataGridView. Это означает, что при выборе категории в первом представлении продукты для этой категории будут автоматически использоваться во втором представлении.Используя глиф
Настройка отображаемых элементов
По умолчанию столбец создается в DataGridView каждом свойстве привязанных типов. Кроме того, значения для каждого из этих свойств можно изменить пользователем. Однако некоторые значения, такие как значения первичного ключа, концептуально доступны только для чтения, и поэтому не следует изменять. Кроме того, некоторые свойства, такие как CategoryId свойство внешнего ключа и Category навигация, не полезны для пользователя, и поэтому их следует скрыть.
Совет
Обычно скрытие свойств первичного ключа в реальном приложении. Они остаются видимыми здесь, чтобы легко увидеть, что EF Core делает за кулисами.
Щелкните правой кнопкой мыши первый
DataGridViewи выберите пункт "Изменить столбцы...".
CategoryIdСделайте столбец, представляющий первичный ключ, только для чтения и нажмите кнопку "ОК".
Щелкните правой кнопкой мыши второй
DataGridViewи выберите пункт "Изменить столбцы...".ProductIdСделайте столбец доступным только для чтения и удалитеCategoryIdCategoryстолбцы, а затем нажмите кнопку "ОК".
Подключение к EF Core
Теперь приложению требуется небольшой объем кода для подключения EF Core к элементам управления, привязанным к данным.
MainFormОткройте код, щелкнув файл правой кнопкой мыши и выбрав "Просмотреть код".
Добавьте частное поле для хранения
DbContextсеанса и добавьте переопределения дляOnLoadметодов иOnClosingметодов. Код должен выглядеть следующим образом:
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
namespace GetStartedWinForms
{
public partial class MainForm : Form
{
private ProductsContext? dbContext;
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.dbContext = new ProductsContext();
// Uncomment the line below to start fresh with a new database.
// this.dbContext.Database.EnsureDeleted();
this.dbContext.Database.EnsureCreated();
this.dbContext.Categories.Load();
this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
this.dbContext?.Dispose();
this.dbContext = null;
}
}
}
Метод OnLoad вызывается при загрузке формы. В настоящее время
- Создается экземпляр
ProductsContext, который будет использоваться для загрузки и отслеживания изменений в продуктах и категориях, отображаемых приложением. -
EnsureCreatedвызывается дляDbContextсоздания базы данных SQLite, если она еще не существует. Это быстрый способ создания базы данных при создании прототипов или тестировании приложений. Однако если модель изменяется, необходимо удалить базу данных, чтобы ее можно было создать еще раз. (СтрокаEnsureDeletedможет быть незакомментирована, чтобы легко удалить и повторно создать базу данных при запуске приложения.) Вместо этого можно использовать миграции EF Core для изменения и обновления схемы базы данных без потери данных. -
EnsureCreatedтакже заполняет новую базу данных данными, определенными в методеProductsContext.OnModelCreating. - Метод
Loadрасширения используется для загрузки всех категорий из базы данных вDbContextбазу данных. Теперь эти сущности будут отслеживатьсяDbContextпользователем, которые будут обнаруживать любые изменения, внесенные при изменении категорий пользователем. - Свойство
categoryBindingSource.DataSourceинициализировано в категории, отслеживаемые даннымиDbContext. Это делается путем вызоваLocal.ToBindingList()CategoriesDbSetсвойства.Localпредоставляет доступ к локальному представлению отслеживаемых категорий с событиями, которые подключены к локальным данным, чтобы обеспечить синхронизацию локальных данных с отображаемыми данными и наоборот.ToBindingList()предоставляет эти данные в видеIBindingListпривязки данных Windows Forms.
Метод OnClosing вызывается при закрытии формы. В настоящее время удаляется, DbContext что гарантирует, что все ресурсы базы данных будут освобождены, и dbContext поле имеет значение NULL, чтобы его нельзя было использовать снова.
Заполнение представления "Продукты"
Если приложение запущено на этом этапе, оно должно выглядеть примерно так:
Обратите внимание, что категории были загружены из базы данных, но таблица продуктов остается пустой. Кроме того, кнопка "Сохранить " не работает.
Чтобы заполнить таблицу продуктов, EF Core необходимо загрузить продукты из базы данных для выбранной категории. Чтобы достичь этого, выполните указанные ниже действия.
В конструкторе основной формы выберите
DataGridViewкатегории.В разделе "Свойства"
DataGridViewвыберите события (кнопка молнии) и дважды щелкните событие SelectionChanged.
Это создаст заглушку в основном коде формы для события, которое будет запущено всякий раз, когда изменяется выбор категории.
Введите код для события:
private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
{
if (this.dbContext != null)
{
var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;
if (category != null)
{
this.dbContext.Entry(category).Collection(e => e.Products).Load();
}
}
}
В этом коде, если существует активный (непустой) DbContext сеанс, мы получаем Category экземпляр, привязанный к выбранной строке текущей DataViewGridстроки. (Это может быть null , если выбрана окончательная строка в представлении, которая используется для создания новых категорий.) Если выбрана категория, необходимо загрузить продукты, DbContext связанные с этой категорией. Способы выполнения этих целей:
- Получение экземпляра
EntityEntryCategory(dbContext.Entry(category)) - Предоставление EF Core знать, что мы хотим работать с
Productsнавигацией по коллекции этогоCategory(.Collection(e => e.Products)) - И, наконец, сообщите EF Core, что мы хотим загрузить коллекцию продуктов из базы данных (
.Load();)
Совет
При Load вызове EF Core будет получать доступ только к базе данных для загрузки продуктов, если они еще не загружены.
Если приложение запущено снова, оно должно загружать соответствующие продукты всякий раз, когда выбрана категория:
Сохранение изменений
Наконец, кнопка "Сохранить" может быть подключена к EF Core, чтобы все изменения, внесенные в продукты и категории, сохранялись в базе данных.
В конструкторе основной формы нажмите кнопку "Сохранить ".
В разделе "Свойства"
Buttonвыберите события (кнопка молнии) и дважды щелкните событие Click.
Введите код для события:
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
Этот код вызывает SaveChangesDbContextобъект, который сохраняет все изменения, внесенные в базу данных SQLite. Если изменения не были внесены, это no-op, и вызов базы данных не выполняется. После сохранения DataGridView элементы управления обновляются. Это связано с тем, что EF Core считывает созданные значения первичного ключа для любых новых продуктов и категорий из базы данных. Вызов Refresh обновляет отображение с этими созданными значениями.
Окончательное приложение
Ниже приведен полный код основной формы:
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
namespace GetStartedWinForms
{
public partial class MainForm : Form
{
private ProductsContext? dbContext;
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.dbContext = new ProductsContext();
// Uncomment the line below to start fresh with a new database.
// this.dbContext.Database.EnsureDeleted();
this.dbContext.Database.EnsureCreated();
this.dbContext.Categories.Load();
this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
this.dbContext?.Dispose();
this.dbContext = null;
}
private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
{
if (this.dbContext != null)
{
var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;
if (category != null)
{
this.dbContext.Entry(category).Collection(e => e.Products).Load();
}
}
}
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
}
}
Теперь приложение можно запускать, а продукты и категории можно добавлять, удалять и изменять. Обратите внимание, что если кнопка "Сохранить " нажимается перед закрытием приложения, все внесенные изменения будут храниться в базе данных и повторно загружаться при повторном запуске приложения. Если элемент "Сохранить " не щелкается, все изменения теряются при повторном запуске приложения.
Совет
Новую категорию или продукт можно добавить DataViewControl в пустую строку в нижней части элемента управления. Строку можно удалить, выбрав ее и нажав клавишу Del .
Перед сохранением
После сохранения
Обратите внимание, что значения первичного ключа для добавленной категории и продуктов заполняются при нажатии кнопки "Сохранить ".