SQLite+Qt 图书管理系统设计(具体实现)

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

    /*---- LOAD IN DASTABASE ----*/

    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);

    }

}


界面:

 

 SQLite+Qt 图书管理系统设计(具体实现)

SQLite+Qt 图书管理系统设计(具体实现)


SQLite+Qt 图书管理系统设计(具体实现)

 

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;

}

 

界面:


单本插入:

SQLite+Qt 图书管理系统设计(具体实现)

SQLite+Qt 图书管理系统设计(具体实现)

删除:

SQLite+Qt 图书管理系统设计(具体实现)

批量入库(QSqlRecord介绍时附过相关代码)

SQLite+Qt 图书管理系统设计(具体实现)

SQLite+Qt 图书管理系统设计(具体实现)

3.图书查询

模糊查询 使用”$”匹配

SQLite+Qt 图书管理系统设计(具体实现)

4.借书

查询信息

SQLite+Qt 图书管理系统设计(具体实现)

无库存

SQLite+Qt 图书管理系统设计(具体实现)

超过借书限制

SQLite+Qt 图书管理系统设计(具体实现)

5.还书

1.      借书证管理

SQLite+Qt 图书管理系统设计(具体实现)

 SQLite+Qt 图书管理系统设计(具体实现)

 

2.      显示

 SQLite+Qt 图书管理系统设计(具体实现)SQLite+Qt 图书管理系统设计(具体实现)

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