https://github.com/birdy-C/BookSystem.git
詳細設計
SQLite是一款輕型的資料庫,占用資源低,與Qt的連接配接便易。
資料庫邏輯結構設計
建立
PRAGMA foreign_keys = ON; ----------------------------------------------------------------------------------------------- create table type( Book_type nvarchar(10) primary key , Type_number int NOT NULL UNIQUE , check (Type_number >0) ); ---------------------------------------------------------------------------------------------- create table book( Book_ID int primary key , Type nvarchar(10) REFERENCES type(Book_type) , Title nvarchar , Publisher nvarchar , Publish_year int check(publish_year>1800 ) , Author NVARCHAR , Price decimal(6,2) , Number int check(Number>=0) , Stocks int check(Stocks>=0) ); --------------------------臨時表,處理批量入庫------------------------------------- create table book_temp( Type nvarchar(10) , Title nvarchar , Publisher nvarchar , Publish_year int , Author NVARCHAR , Price decimal(6,2) , Number int ); ------------------------------------------------------------------------------------------------ create table library_card( card_ID int primary key , Username varchar(10) , Company nvarchar , Type varchar(10) check (Type in ( 'student', 'teacher' ) )); ----------------------------------------------------------------------------------------------- create table manager( manager_ID int primary key , Password varchar(10) not null , Name varchar(10) , Connection int ); ----------------------------------------------------------------------------------------------- create table record ( Book_ID int REFERENCES book(Book_ID) , card_ID int REFERENCES Library_card(card_ID) , borrow_data data , return_data data check ( return_data >= borrow_data ) , manager_ID int REFERENCES manager(manager_ID) , primary key(Book_ID,card_ID) ); |
觸發器
--------------檢查出版年份----------------- CREATE TRIGGER Tr_check_date AFTER insert ON book FOR EACH ROW WHEN( (select Book_ID from book where publish_year > (SELECT strftime('%Y',date('now')) ) )is not null) BEGIN SELECT RAISE(ROLLBACK, 'IMPOSSIBLE DATE') ; END; --------------檢查輸入時 庫存與數量是否相等----------------- CREATE TRIGGER Tr_check_number BEFORE insert ON book FOR EACH ROW WHEN ( new.Number <> new.Stocks ) BEGIN SELECT RAISE(ROLLBACK, 'ANY WRONG ABOUT NUMBER?'); END; --------------借出檢查是否有餘量----------------- CREATE TRIGGER Tr_borrow_check BEFORE insert ON record FOR EACH ROW WHEN 0=(select Stocks from book where Book_ID=new.Book_ID) BEGIN SELECT RAISE(ROLLBACK, 'NO REMAINING') ; END; --------------借出檢查借書證 老師5學生3----------------- CREATE TRIGGER Tr_borrow_card AFTER insert ON record FOR EACH ROW WHEN ( (select count(*) from record join (select card_ID as S from library_card where card_ID = new.card_ID and Type = 'student') on record.card_ID = S ) >3 --學生 or (select count(*) from record join (select card_ID as T from library_card where card_ID = new.card_ID and Type = 'teacher') on record.card_ID = T ) >5 --老師 ) BEGIN SELECT RAISE(ROLLBACK, 'MORE THAN PERMITTED') ; END; --------------借出更新資料----------------- CREATE TRIGGER Tr_borrow AFTER insert ON record FOR EACH ROW BEGIN UPDATE Book SET Stocks = ( select Stocks - 1 FROM Book WHERE Book_ID = new.Book_ID ) WHERE Book_ID = new.Book_ID ; END; --------------傳回更新資料----------------- CREATE TRIGGER Tr_return AFTER delete ON record FOR EACH ROW BEGIN UPDATE Book SET Stocks = ( select Stocks + 1 FROM Book WHERE Book_ID = old.Book_ID ) WHERE Book_ID = old.Book_ID ; END; --------------插入檢查是否已經存在----------------- ---------這一段大概有很多可以優化的地方吧…… CREATE TRIGGER Tr_check_insert AFTER insert ON book FOR EACH ROW WHEN ( ( select count(Book_ID) from book where Type = new.Type and Title = new.Title and Publisher = new.Publisher and Publish_year = new.Publish_year and Author = new.Author and Price = new.Price ) >1--except for new ) BEGIN UPDATE Book SET Stocks = ( select Stocks + new.Stocks FROM Book where Type = new.Type and Title = new.Title and Publisher = new.Publisher and Publish_year = new.Publish_year and Author = new.Author and Price = new.Price ) where Type = new.Type and Title = new.Title and Publisher = new.Publisher and Publish_year = new.Publish_year and Author = new.Author and Price = new.Price; UPDATE Book SET Number = ( select Number + new.Number FROM Book where Type = new.Type and Title = new.Title and Publisher = new.Publisher and Publish_year = new.Publish_year and Author = new.Author and Price = new.Price ) where Type = new.Type and Title = new.Title and Publisher = new.Publisher and Publish_year = new.Publish_year and Author = new.Author and Price = new.Price; DELETE FROM Book WHERE Book_ID = new.Book_ID; END; |
圖書管理系統設計
一、主要類說明(SQL相關)以及主要使用
QsqlDatabase提供了一個Qt和DB的連接配接口。
以下代碼為資料庫連接配接代碼,并且打開資料庫檔案DBSYSTEN.db
db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("DBSYSTEM.db"); if (!db.open()) { QMessageBox::warning(0, QObject::tr("Database Error"),db.lastError().text()); qDebug() << QString("LOAD_IN"); returnfalse; } |
此外可以通過boolQSqlDatabase::transaction(),bool QSqlDatabase::commit(),bool QSqlDatabase::rollback()來實作相當于撤銷和儲存的操作。
QsqlQuery提供了一個SQL語句的運作接口。
如下面語句,實作的是讀取Book_id對應書的庫存和數量。
QSqlQuery query_getStocks("select Stocks,Number from book where Book_id = '"+ ID +"'"); int Stocks_int, All_int; if (query_getStocks.next()) { Stocks_int = query_getStocks.value(0).toInt(); All_int = query_getStocks.value(1).toInt(); } else { QMessageBox::warning(0,QObject::tr("INACCURACY DATA"),"Please check the ID"); return; } |
QsqlError提供SQL資料庫的錯誤資訊。
在這裡主要用于處理QSqlError QSqlDatabase::lastError()const傳回的錯誤。
QSqlTableModel 可以很友善地為一個table(或者view)提供可編輯的形式。
在ui界面上顯示table book的代碼如下:
select_model = newQSqlTableModel(this); select_model->setTable("book"); ui.tableView_select->setModel(select_model); select_model->select(); ui.tableView_select->setEditTriggers(QAbstractItemView::NoEditTriggers);//不可編輯 ui.tableView_select->setSelectionBehavior(QAbstractItemView::SelectRows);//整行選中 |
QSqlRecord讀取資料庫記錄。
下為讀取臨時table book_temp中的代碼插入book中(SL_insert_book為插入的函數)的代碼。
for (int i = select_model_insert2->rowCount()-1; i >= 0; i--) { QSqlRecord record = select_model_insert2->record(i); bool ok; ok = SL_insert_book ( record.value("Type").toString(), record.value("Title").toString(), record.value("Publisher").toString(), record.value("Publish_year").toString(), record.value("Author").toString(), record.value("Price").toString(), record.value("Number").toString() ); if(ok) { select_model_insert2->removeRow(i); } } |
QModelIndex這裡用來處理讀取QSqlTableModel的選中資料。
讀取選中的資料類型,并依次修改ui.lineEdit_8的資料,代碼如下:
voidBookSystem::SL_insert1_selectType(constQModelIndex &, constQModelIndex &) { QModelIndex index=ui.tableView_insert1_type->currentIndex(); QModelIndex i1 = index.sibling(index.row(), 0); QString str1 = i1.data().toString(); ui.lineEdit_8->setText(str1); } |
二、主要類說明(界面相關)
控件 | 信号 |
tabWidget | currentChanged(int) |
lineEdit | textEdited(const QString &) |
pushButton | clicked() |
checkBox | released() |
radioButton | released() |
spinBox | valueChanged(int) |
doubleSpinBox | valueChanged(double) |
tableView->selectionModel() | currentRowChanged(const QModelIndex &,const QModelIndex &) |
三、具體實作及主要界面
1.管理者登陸
檢查使用者是否存在
boolBookSystem:: checkManager() { QSqlQuery query_temp("select manager_ID, Name from manager where manager_ID = '"+ ui.lineEdit_18->text() +"'AND Password = '"+ ui.lineEdit_17->text()+"';"); if (query_temp.next()) { manager_ID = query_temp.value(0).toInt(); manager_name = query_temp.value(1).toString(); } else { QMessageBox::warning(0,QObject::tr("NO SUCH INFORMATION"),"make sure you add the accurate information"); returnfalse; } returntrue; } |
更新界面
voidBookSystem::SL_user_loadin() { if (false == checkManager()) { ui.lineEdit_17->setText(""); return; } QMessageBox::about(0,QObject::tr("LOAD IN"),"Welcome ! "+ manager_name+"."); load_statues = true; //manager_ID = ui.lineEdit_18->text().toInt(); ui.label_24->setText("Welcome ! "+ manager_name+"."); ui.lineEdit_17->setText(""); ui.lineEdit_18->setText(""); { ui.tabWidget->addTab(ui.tab_2,QString::fromLocal8Bit("單本插入/删除")); ui.tabWidget->addTab(ui.tab_3,QString::fromLocal8Bit("批量入庫")); ui.tabWidget->addTab(ui.tab_4,QString::fromLocal8Bit("借閱管理")); ui.tabWidget->addTab(ui.tab_5,QString::fromLocal8Bit("使用者資訊管理")); ui.tabWidget->addTab(ui.tab_6,QString::fromLocal8Bit("建立使用者")); ui.tabWidget->addTab(ui.tab_7,QString::fromLocal8Bit("借書記錄")); ui.tabWidget->addTab(ui.tab_8,QString::fromLocal8Bit("管理者資訊")); connect(ui.tabWidget, SIGNAL(currentChanged(int)),this,SLOT(empty(int))); } { //set the buttom bool ok =false; ui.label_25->setVisible(ok); ui.label_26->setVisible(ok); ui.lineEdit_17->setVisible(ok); ui.lineEdit_18->setVisible(ok); ui.pushButton_12->setVisible(ok); ui.label_24->setVisible(!ok); ui.pushButton->setVisible(!ok); } } |
界面:
2.圖書入庫
核心代碼
voidBookSystem::SL_insert1() { if(SL_insert_book(ui.lineEdit_8->text(), ui.lineEdit_4->text(), ui.lineEdit_5->text(), ui.lineEdit_6->text(), ui.lineEdit_7->text(), ui.lineEdit_9->text(), ui.lineEdit_10->text())) { select_model_insert1->select();//更新顯示 QMessageBox::about(0,QObject::tr("SUCCESS"),"Success in inserting book <"+ ui.lineEdit_4->text()+">"); SL_insert1_empty(); } } boolBookSystem::SL_insert_book(QStringType,QStringTitle,QStringPublisher, QStringPublish_year,QString Author,QStringPrice,QStringNumber) { QString ID; //如果标題為空 if (""==Title ) { QMessageBox::warning(0,QObject::tr("INACCURACY DATA"),"Please put in accurate name"); return false; } //如果得到的是零或者負數 int number_in =Number.toInt(); if (number_in <= 0) { QMessageBox::warning(0,QObject::tr("INACCURACY DATA"),"Please check the number"); return false; } QString number =QString::number(number_in, 10);//取整 //根據type生成ID QSqlQuery query_getID("select MAX(Book_id)+1 from book where Type = '"+Type+"'"); if (query_getID.next()) { ID = query_getID.value(0).toString(); } if (ID=="")//如果這個類型還沒有書 { QSqlQuery query_temp("select Type_number * 1000 + 1 from type where Book_type = '"+Type+"'"); ui.plainTextEdit_3->setPlainText(ID); if (query_temp.next()) { ID = query_temp.value(0).toString(); } else { QMessageBox::warning(0,QObject::tr("NO SUCH TYPE"),"make sure you add the accuracy type"); returnfalse; } } //插入 QSqlQuery insert; insert.prepare("INSERT INTO book (Book_id,Type,Title,Publisher,Publish_year,Author,Price,Number,Stocks) " "VALUES (?,?,?,?,?,?,?,?,?);"); insert.addBindValue(ID); insert.addBindValue(Type); insert.addBindValue(Title); insert.addBindValue(Publisher); insert.addBindValue(Publish_year); insert.addBindValue(Author); insert.addBindValue(Price); insert.addBindValue(Number); insert.addBindValue(Number); insert.exec(); if (!insert.isActive()) { QMessageBox::warning(0,QObject::tr("Database Error"),"Please check the input ,especially the accurcy in publish year," "or maybe the ID need to be reset."); //資料庫傳回錯誤的幾種可能性 1.主鍵限制即 ID的生成有一定不合理性 2.trigger的限制 年份大于1800 小于現在的年份 returnfalse; } returntrue; } |
界面:
單本插入:
删除:
批量入庫(QSqlRecord介紹時附過相關代碼)
3.圖書查詢
模糊查詢 使用”$”比對
4.借書
查詢資訊
無庫存
超過借書限制
5.還書
1. 借書證管理
2. 顯示
3. 撤銷操作
if (!db.rollback()) { QMessageBox::warning(0,QObject::tr("Database Error"), db.lastError().text()); } else { QMessageBox::about(0,QObject::tr("Database Error"),"Success in Rollback"); } |
附錄
代碼下載下傳
https://github.com/birdy-C/BookSystem.git