laravel-admin 一對多,多對多關係實踐(基於學生-成績-課程-教師關係)

首先說一下業務實現的基礎,基於一道題目

假設教學管理規定:

一個學生可選修多門課,一門課有若干學生選修;
一個教師可講授多門課,一門課只有一個教師講授;
一個學生選修一門課,僅有一個成績。
學生的屬性有學號、學生姓名;教師的屬性有教師編號,教師姓名;課程的屬性有課程號、課程名。

要求:根據上述語義畫出ER 圖,要求在圖中畫出實體的屬性並註明聯繫的類型;

生成四個表的表結構,學生表,成績表(關聯表),課程表,教師表

CREATE TABLE `students` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `stu_no` int(11) NOT NULL COMMENT '學號',
 `name` varchar(50) NOT NULL COMMENT '姓名',
 `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`id`),
 UNIQUE KEY `stu_no` (`stu_no`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='學生表'

CREATE TABLE `results` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `stu_no` int(11) NOT NULL COMMENT '學號',
 `cou_no` int(11) NOT NULL COMMENT '課程號',
 `grade` int(11) NOT NULL DEFAULT '0' COMMENT '分數',
 `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='成績表'

CREATE TABLE `courses` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `cou_no` int(11) NOT NULL COMMENT '課程號',
 `name` varchar(50) NOT NULL COMMENT '課程名',
 `teach_no` int(11) NOT NULL COMMENT '教師號',
 `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`id`),
 UNIQUE KEY `cou_no` (`cou_no`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='課程表'

CREATE TABLE `teachers` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `teach_no` int(11) NOT NULL COMMENT '教師號',
 `name` varchar(30) NOT NULL COMMENT '姓名',
 `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`id`),
 UNIQUE KEY `teach_no` (`teach_no`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='教師表'

創建各自的模型

class Student extends Model
{
    //模型是寫給自己使用的
    //學生和課程多對多,但是查詢出來的數據只有課程裏面相關的數據,想要獲取課程的成績數據還要再次查詢
    public function courses(){
        $pivot_table = 'results';//中間表
        $related_model = '\App\Models\Course';//另外一個model
        //13,24的情況
        return $this->belongsToMany($related_model,$pivot_table,'stu_no','cou_no','stu_no','cou_no');
    }

    //學生和成績一對多
    public function results(){
        //外鍵就是不是自己表的鍵
        return $this->hasMany(Result::class,'stu_no','stu_no');
    }
}

class Result extends Model{
}

class Course extends Model
{
    //課程和學生多對多
    public function students(){
        $pivot_table = 'results';//關聯表
        $related_model = '\App\Models\Student';//另外一個model
        return $this->belongsToMany($related_model,$pivot_table,'cou_no','cou_no');
    }

    //多個課程對應一個教師
    public function teacher(){
        //foreignKey的意思是當前表存在的和另外表相關連的外鍵,也就是課程表對應的鍵名
        //ownerKey的意思擁有者的鍵名,也就是教師表的鍵名
        return $this->belongsTo(Teacher::class,'teach_no','teach_no');
    }

}
class Teacher extends Model
{
    //教師和課程1對多,一個教師對應多個課程
    public function courses(){
        return $this->hasMany(Course::class,'teach_no','teach_no');
    }
}

我的模型都是創建到Models下的,命令行下執行下面的語句,創建控制器

php artisan admin:make StudentController --model=App\Models\Student
php artisan admin:make ResultController --model=App\Models\Result
php artisan admin:make CourseController --model=App\Models\Course
php artisan admin:make TeacherController --model=App\Models\Teacher

路由app/Admin/routes.php,添加路由

$router->resource('students', StudentController::class);

$router->resource('results', ResultController::class);

$router->resource('courses', CourseController::class);

$router->resource('teachers', TeacherController::class);

添加菜單,訪問http://127.0.0.5/admin/auth/menu

課程和教師是多對一的關係

展示課程對應的教師數據,上面的Course model中寫好了teacher方法,直接使用就好了,課程表中默認是沒有教師姓名字段的,通過teacher()可以訪問teachers表的所有字段

 

多對多關係

學生數據頁面默認是隻展示學生的數據,現在需求是展示出學生選修的課程,以及對應選修課程的成績;

學生和課程是多對多,學生和成績是一對多,對應的model代碼如下

class Student extends Model
{
    //學生和課程多對多,但是查詢出來的數據只有課程裏面相關的數據,想要獲取課程的成績數據還要再次查詢
    public function courses(){
        $pivot_table = 'results';//中間表
        $related_model = '\App\Models\Course';//另外一個model
        //13,24的情況
        return $this->belongsToMany($related_model,$pivot_table,'stu_no','cou_no','stu_no','cou_no');
    }

    //學生和成績一對多
    public function results(){
        //外鍵就是不是自己表的鍵
        return $this->hasMany(Result::class,'stu_no','stu_no');
    }
}

對應的控制器代碼如下:

protected function grid()
    {
        $grid = new Grid(new Student);

        $grid->id('Id');
        $grid->stu_no('學號');
        $grid->name('姓名');
        /*$grid->courses('課程',function ($courses){
            //資源路由數據,建議打開註釋看下
        });*/
        $grid->courses('選修課程')->display(function ($courses) {
            $courses = array_map(function ($course) {
                return "<span class='label label-success'>{$course['name']}</span>";
            }, $courses);
            return join('&nbsp;', $courses);
        });
        $grid->results('成績')->display(function ($results) {
            $results = array_map(function ($result) {
                return "<span class='label label-warning'>{$result['grade']}</span>";
            }, $results);
            return join('&nbsp;', $results);
        });

        return $grid;
    }

頁面展示效果如下

 

從模型的使用上感覺有時候可以用一條語句就能夠查詢獲取到數據的,但是卻偏要繞到另外一個表再次獲取有點麻煩,所以就想到能不能用DB執行查詢,再把數據展示到頁面中去(個人意見)

DB實現

在成績數據展示頁面,想要展示成績對應的學生姓名,成績對應的科目,之前成績表默認只存儲了stu_no,cou_no字段,如果按照model的方式需要在查詢了成績表的基礎上,還要查詢學生表,課程表;展示DB實現代碼如下:

model中需要重寫paginate()和with()方法

class Result extends Model
{
    //使用DB查詢獲取到的數據,覆蓋paginate()和with()方法
    public function paginate(){
        $perPage = Request::get('per_page', 2);

        $page = Request::get('page', 1);

        $start = ($page-1)*$perPage;

        $total = DB::table('results')->count();

        /*DB::connection()->enableQueryLog();
        //查詢獲取到成績所屬學生姓名,所屬課程
        $result = DB::table('students as s')->join('results as r','s.stu_no','=','r.stu_no')
            ->join('courses as c','r.cou_no','=','c.cou_no')
            ->select('r.*','s.name as s_name','c.name as c_name')->get();
        $log = DB::getQueryLog();
        dd($log);*/

        //加入分頁的內容到sql中去
        $sql = "select `r`.*, `s`.`name` as `s_name`, `c`.`name` as `c_name` from `students` as `s` inner join `results` as `r` on `s`.`stu_no` = `r`.`stu_no` inner join `courses` as `c` on `r`.`cou_no` = `c`.`cou_no`";
        $sql .= " limit $start,$perPage";

        $result = DB::select($sql);

        $results = static::hydrate($result);

        $paginator = new LengthAwarePaginator($results, $total, $perPage,$page);


        $paginator->setPath(url()->current());
        return $paginator;
    }

    public static function with($relations)
    {
        return new static;
    }

在實現paginate的時候,想要使用DB自帶的paginate()方法,而不是生成分頁對象,但是會報錯;只能寫原生語句;註釋裏面是打印sql的語句;

控制器的代碼如下

protected function grid()
    {
        $grid = new Grid(new Result);

        $grid->id('序號');
        $grid->stu_no('學號')->sortable();//排序操作會出現學生姓名,課程名稱爲空的情況
        $grid->s_name('學生姓名');
        $grid->cou_no('課程號')->sortable();
        $grid->c_name('課程名稱');
        $grid->grade('成績');
        $grid->created_at('創建時間');
        return $grid;
    }

頁面效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章