You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

图书馆管理系统:类实例存入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实时更新

  1. 替换List为ObservableCollection:WPF中ObservableCollection会自动通知UI数据变化
public ObservableCollection<Item> Items = new ObservableCollection<Item>();
  1. 添加刷新方法
public void RefreshDataGrid()
{
    Items.Clear();
    var dbItems = DbService.GetAllItems();
    foreach(var item in dbItems)
    {
        Items.Add(item);
    }
    // 如果是WinForms,需要调用DataGrid.Refresh();
}
  1. 解决DataGrid为空问题
  • 检查LibraryTable是否有数据,连接字符串是否正确
  • 确保DataGrid的ItemsSource绑定到Items集合:比如WPF中DataGrid.ItemsSource = mainLibrary.Items;
  • 初始化MainLibrary时调用RefreshDataGrid()加载初始数据

五、SqlService优化建议

  1. 封装内部字段,避免暴露_connection、_cmd等公共字段
  2. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:55:24