图书馆管理系统:类实例存入SQL库与DataGrid更新问题
图书馆管理系统SQL存储与DataGrid实时更新问题
问题描述
我正在开发一款图书馆管理系统,管理员可通过GUI添加书籍或游戏。目前遇到以下问题:
- 如何将类实例存入SQL本地数据库,同时保持显示馆藏物品的DataGrid实时更新?
- 纠结两种方案:先创建类实例再批量传入数据库,还是创建实例后立即存入库,再从库中拉取数据到列表并绑定DataGrid?若选后者,如何将数据库数据转换为类实例?
另外,我刚接触SQL,已实现DataGrid与数据库的绑定,但DataGrid为空。现有代码中,尝试通过类属性将Book实例存入数据库的BookToDb方法未成功,希望得到解决方案。
现有代码
管理类
namespace TheLastLibrary.Classes { public class MainLibrary { public List<Item> Items = new List<Item>(); SqlService DbService; public MainLibrary() { //DbService = new SqlService(); //DbService.SqlQuery("SELECT * FROM LibraryTable"); //DbService._connection.Open(); //DbService._reader = DbService._cmd.ExecuteReader(); //DbService._dataTable.Load(DbService._reader); //DbService._connection.Close(); } public void AddBook(string name, string description, double price, int discount, int minimumAge, int quantity, BooksGenres b, string author) { Items.Add(new Book(name, description, price, discount, minimumAge, quantity, b, author)); BookToDb(name); } public void AddGame(string name, string description, double price, int discount, int minimumAge, int quantity, GamesGenres g) { Items.Add(new Game(name, description, price, discount, minimumAge, quantity, g)); } public List<Item> GetItems() { return Items; } void UpdateName(Item i, string NewName) { i.Name = NewName; } void UpdatePrice(Item i, double NewPrice) { i.Price = NewPrice; } void UpdateDiscount(Item i, int NewDiscount) { i.Discount = NewDiscount; } void UpdateQuantity(Item i, int NewQuantity) { i.Quantity = NewQuantity; } Item SearchByName(string name) { foreach (Item i in Items) { if (i == null) throw new ArgumentNullException(); if (i.Name == name) return i; } return null; } Item SearchById(int id) { foreach (Item i in Items) { if (i == null) throw new ArgumentNullException(); if (i.Id == id) return i; } return null; } Item SearchByPriceRange(int min, int max) { foreach (Item i in Items) { if (i == null) throw new ArgumentNullException(); if (i.Price <= max && i.Price >= min) return i; } return null; } Item SearchByMinimumAge(int min) { foreach (Item i in Items) { if (i == null) throw new ArgumentNullException(); if (i.MinimumAge <= min && i.Price >= min) return i; } return null; } Item SearchByGenre(string genre) { foreach (Item i in Items) { if (i == null) throw new ArgumentNullException(); if (i.Genre == genre) return i; } return null; } public void BookToDb(string name) { Book B = (Book)SearchByName(name); foreach (PropertyInfo prop in typeof(Book).GetProperties()) { foreach(DataColumn Dc in DbService._dataTable.Columns) { if (Dc.ColumnName == prop.Name) { DbService._connection.Open(); DbService.SqlQuery($"INSERT INTO LibraryTable ({Dc.ColumnName}) VALUES {prop.GetValue(B)}"); DbService._connection.Close(); } } } } }
尝试通过属性将实例传入数据库未成功
SQL服务类
internal class SqlService { public SqlConnection _connection { get;} public SqlCommand _cmd; private SqlDataAdapter _adapter; public SqlDataReader _reader { get; set; } public DataTable _dataTable { get; set; } public SqlService() { _connection = new SqlConnection(@"Data Source=DESKTOP-9BRI5GA;Initial Catalog=LibraryDb;Integrated Security=True"); SqlQuery("SELECT * FROM LibraryTable"); _connection.Open(); _reader = _cmd.ExecuteReader(); _dataTable.Load(_reader); _connection.Close(); } public void SqlQuery(string QueryText) { _cmd = new SqlCommand(QueryText, _connection); } public DataTable QueryEx() { _adapter = new SqlDataAdapter(_cmd); _dataTable = new DataTable(); _adapter.Fill(_dataTable); return _dataTable; } public void NonQueryEx() { _cmd.ExecuteNonQuery(); } //public bool InsertBulkRecords<T>(List<T> records) //{ // bool Inserted = false; // return Inserted; //} //public DataTable GetTable<T>(List<T> records) //{ // var type = typeof(T); // return _dataTable; //} }
解决方案
一、方案选择:优先实时入库+拉取绑定
推荐创建实例后立即存入数据库,再从库中拉取数据绑定DataGrid,理由:
- 数据一致性强:避免内存列表与数据库数据脱节
- 实时更新简单:操作数据库后重新拉取数据即可刷新UI
- 扩展性好:支持多用户场景,其他用户的操作能同步到本地UI
二、修复BookToDb方法的问题
你的BookToDb存在4个核心问题:DbService未初始化、INSERT语句错误、SQL注入风险、连接管理混乱。修改后的代码如下:
修改BookToDb方法(参数化查询)
public void BookToDb(Book book) { // 初始化DbService if (DbService == null) DbService = new SqlService(); // 一次性插入所有字段的参数化SQL string insertSql = @"INSERT INTO LibraryTable (Name, Description, Price, Discount, MinimumAge, Quantity, Genre, Author) VALUES (@Name, @Description, @Price, @Discount, @MinimumAge, @Quantity, @Genre, @Author)"; DbService.SqlQuery(insertSql); // 添加参数,避免SQL注入 DbService._cmd.Parameters.AddWithValue("@Name", book.Name); DbService._cmd.Parameters.AddWithValue("@Description", book.Description); DbService._cmd.Parameters.AddWithValue("@Price", book.Price); DbService._cmd.Parameters.AddWithValue("@Discount", book.Discount); DbService._cmd.Parameters.AddWithValue("@MinimumAge", book.MinimumAge); DbService._cmd.Parameters.AddWithValue("@Quantity", book.Quantity); DbService._cmd.Parameters.AddWithValue("@Genre", book.Genre.ToString()); // 枚举转字符串存储 DbService._cmd.Parameters.AddWithValue("@Author", book.Author); try { DbService._connection.Open(); DbService.NonQueryEx(); } finally { DbService._connection.Close(); } }
修改AddBook方法(直接传入实例)
public void AddBook(string name, string description, double price, int discount, int minimumAge, int quantity, BooksGenres b, string author) { Book newBook = new Book(name, description, price, discount, minimumAge, quantity, b, author); Items.Add(newBook); BookToDb(newBook); // 刷新DataGrid RefreshDataGrid(); }
三、数据库数据转类实例的方法
在SqlService中添加查询映射方法,将数据库记录转换为Item/Book/Game实例:
// SqlService中新增方法 public List<Item> GetAllItems() { List<Item> items = new List<Item>(); string query = "SELECT * FROM LibraryTable"; SqlQuery(query); try { _connection.Open(); _reader = _cmd.ExecuteReader(); while (_reader.Read()) { // 假设表中有Type字段区分书籍/游戏 string itemType = _reader["Type"].ToString(); if(itemType == "Book") { Book book = new Book( _reader["Name"].ToString(), _reader["Description"].ToString(), Convert.ToDouble(_reader["Price"]), Convert.ToInt32(_reader["Discount"]), Convert.ToInt32(_reader["MinimumAge"]), Convert.ToInt32(_reader["Quantity"]), (BooksGenres)Enum.Parse(typeof(BooksGenres), _reader["Genre"].ToString()), _reader["Author"].ToString() ); book.Id = Convert.ToInt32(_reader["Id"]); items.Add(book); } else if(itemType == "Game") { Game game = new Game( _reader["Name"].ToString(), _reader["Description"].ToString(), Convert.ToDouble(_reader["Price"]), Convert.ToInt32(_reader["Discount"]), Convert.ToInt32(_reader["MinimumAge"]), Convert.ToInt32(_reader["Quantity"]), (GamesGenres)Enum.Parse(typeof(GamesGenres), _reader["Genre"].ToString()) ); game.Id = Convert.ToInt32(_reader["Id"]); items.Add(game); } } } finally { _connection.Close(); } return items; }
四、实现DataGrid实时更新
- 替换List为ObservableCollection:WPF中ObservableCollection会自动通知UI数据变化
public ObservableCollection<Item> Items = new ObservableCollection<Item>();
- 添加刷新方法
public void RefreshDataGrid() { Items.Clear(); var dbItems = DbService.GetAllItems(); foreach(var item in dbItems) { Items.Add(item); } // 如果是WinForms,需要调用DataGrid.Refresh(); }
- 解决DataGrid为空问题
- 检查LibraryTable是否有数据,连接字符串是否正确
- 确保DataGrid的ItemsSource绑定到Items集合:比如WPF中
DataGrid.ItemsSource = mainLibrary.Items; - 初始化MainLibrary时调用RefreshDataGrid()加载初始数据
五、SqlService优化建议
- 封装内部字段,避免暴露_connection、_cmd等公共字段
- 使用using语句自动释放资源,避免连接泄漏:
public void NonQueryEx(string query, SqlParameter[] parameters = null) { using(SqlConnection conn = new SqlConnection(_connection.ConnectionString)) { using(SqlCommand cmd = new SqlCommand(query, conn)) { if(parameters != null) cmd.Parameters.AddRange(parameters); conn.Open(); cmd.ExecuteNonQuery(); } } }
内容的提问来源于stack exchange,提问作者jackson_keshet
相关产品推荐
相关产品推荐

