ThinkPHP 页面跳转和重定向_thinkphp $this->success 重定向到指定页面-CSDN博客

mikel阅读(128)

来源: ThinkPHP 页面跳转和重定向_thinkphp $this->success 重定向到指定页面-CSDN博客

系统Controller类内置跳转方法error和success,分别用于错误提示和成功跳转。
两个方法分别有三个参数:
参数1:提示信息
参数2:跳转地址
参数3:跳转页面等待时间(秒)

$New = M(‘New’); //实例化New对象
$result = $New->add($data);
if($result){
// 成功后跳转到新闻列表页面
$this->success(‘新增成功,即将返回列表页面’, ‘/New/index’);
} else {
// 错误页面的默认跳转页面是返回前一页,通常不需要设置
$this->error(‘新增失败’);
}

success error跳转对应的模板

//默认错误跳转对应的模板文件
‘TMPL_ACTION_ERROR’ => THINK_PATH . ‘Tpl/dispatch_jump.tpl’,
//默认成功跳转对应的模板文件
‘TMPL_ACTION_SUCCESS’ => THINK_PATH . ‘Tpl/dispatch_jump.tpl’,

自定义跳转模板
将模板直接放到项目目录下

//默认错误跳转对应的模板文件
‘TMPL_ACTION_ERROR’ => ‘Common@Public/error’,
//默认成功跳转对应的模板文件
‘TMPL_ACTION_SUCCESS’ => ‘Common@Public/success’,

自定义模板中可以使用模板变量

$message 页面成功提示信息
$error 页面错误提示信息
$waitSecond 跳转等待时间 单位为秒
$jumpUrl 跳转页面地址

重定向
使用constroller的redirect方法来实现页面重定向跳转。

redirect(‘重定向操作地址(一般为[控制器/操作])’,’参数(字符串或者数组)’,’重定向等待时间(秒)’,’重定向提示信息’)

例:

$result = $New->add($data);
if($result){
// 停留5秒后跳转到New模块的category操作,并且显示页面跳转中字样
$this->redirect(‘New/category’, ‘cate_id=2&status=1′, 5,’页面跳转中…’);
} else {
// 错误页面
$this->redirect(‘New/error’);
}
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Cc_Rain0624/article/details/52369441

getimagesize引发failed to open stream: HTTP request failed! 的问题_getimagesize failed to open stream: http request f-CSDN博客

mikel阅读(141)

来源: getimagesize引发failed to open stream: HTTP request failed! 的问题_getimagesize failed to open stream: http request f-CSDN博客

php中getimagesize()引发failed to open stream: HTTP request failed! 的问题

这种一般是由于自己的代码和请求的远程图片编码不一致问题导致

首先你需要统一编码

比如有问题的图片为:$img

处理:

$img = iconv(‘gbk’, ‘utf-8’, $img);

在调用图片函数:

$info = getimagesize($img);

结束~

画外音:有时候iconv会导致一些报错信息,这个在这不讨论,也和这个问题无论,加上这个可以忽略。

iconv(‘gbk’, ‘utf-8//IGNORE’, $url)
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/u011056818/article/details/81539222

failed to open stream: No such file or directory问题解决大全-CSDN博客

mikel阅读(139)

来源: failed to open stream: No such file or directory问题解决大全-CSDN博客

这篇文章主要为大家详细介绍了failed to open stream: No such file or directory问题解决大全,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,有需要的朋友可以收藏方便以后借鉴。

failed to open stream: No such file or directory是PHP站点经常可能会遇到的问题,361源码做了个总结,希望能帮助到一些遇到这个问题的朋友们。

案例一:

(failed to open stream: No such file or directory)在IIS下PHP环境配置的目录权限导致出错的问题

原因及解决方法:

配置环境为 IIS + php

如果确认你的程序在其他环境下下可以正常运行而唯独在Win 下的 IIS 出现类似如下的错误:

Warning: main(./Config.php): failed to open stream: No such file or directory in D:/wwwroot/Demo/Config.php on line 13

Fatal error: main(): Failed opening required ‘./Config.php’ (include_path=’.;c:/php4/pear’) in D:/wwwroot/Core/Config.php on line 13

这个问题主要是 由于Win NTFS盘下去除了everyone 权限引起的, 在安全权限中加个 Internet 来宾账号就解决了.

操作步骤: D盘 -> 属性 -> 安全 -> 添加 用户 IUSR_XXXXX OK

案例二:

问题就是:

Warning: require_once(../lib/DBUtil.class.php) [function.require-once]: failed to open stream: No such file or directory in E:/phppro/dxh/service/ExpertService.class.php on line 2

Fatal error: require_once() [function.require]: Failed opening required ‘../lib/DBUtil.class.php’ (include_path=’.;C:/php5/pear’) in E:/phppro/dxh/service/ExpertService.class.php on line 2

解决方法:

在require时加上dirname(__FILE__),像这样: require_once(dirname(__FILE__).”/../lib/DBUtil.class.php”);
如下理解 require_once实例:
<?php
//如果b.php被其他目录里的a.php文件require 或者 include 去引用的话 require_once(“./c.php”);
//实际上调用的是a.php目录下的c.php require_once(dirname(__FILE__).”/c.php”);
//实际上调用的是b.php目录下的c.php require_once(“c.php”);
//实际上调用的是b.php目录下的c.php
?>
案例三:

运行php网站,出错,内容如下:

Warning: Unknown: failed to open stream: No such file or directory in Unknown on line 0

Fatal error: Unknown: Failed opening required ‘E:/php/www/mrsoft/注册登录模块/index.php’ (include_path=’.;C:/php5/pear’) in Unknown on line 0

解决方法:

apache不能解析上图中“注册登录模块”的中文URL,把它换成英文路径即可。

总结:

关于failed to open stream: No such file or directory出现的问题,大体就分为这3大类型。如果你也遇到了这样的报错,你可以仔细比对属于哪个类型的错误。根据上面的提示和解决办法处理,相信很快就能解决问题。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_64051447/article/details/130746697

PHP使用phpqrcode生成二维码详解 - 掘金

mikel阅读(149)

来源: PHP使用phpqrcode生成二维码详解 – 掘金

1.phpqrcode类文件下载,下载地址: PHP QR Code download | SourceForge.net 。点击Downioad下载

image.png

下载下来的类文件是一个压缩包,里边包含很多文件和演示程序,我们只需要里边的phpqrcode.php这一个文件就可以生成二维码了。它是一个多个类的集合文件,我们需要用到里边的QRcode类(第2963行)的png()方法(第3090行):

image.png

2.PHP环境必须开启支持GD2扩展库支持(一般情况下都是开启状态)

3.PHP代码

3.1. 生成二维码(生成图片文件)   每调用一次都会在本地生成一张二维码图片
php

复制代码
function scerweima($url=''){undefined
    require_once 'phpqrcode.php';
    
    $value = $url;                    //二维码内容
    
    $errorCorrectionLevel = 'L';    //容错级别 
    $matrixPointSize = 5;            //生成图片大小  
    
    //生成二维码图片
    $filename = 'qrcode/'.microtime().'.png';
    QRcode::png($value,$filename , $errorCorrectionLevel, $matrixPointSize, 2);  
  
    $QR = $filename;                //已经生成的原始二维码图片文件  
 
 
    $QR = imagecreatefromstring(file_get_contents($QR));  
  
    //输出图片  
    imagepng($QR, 'qrcode.png');  
    imagedestroy($QR);
    return '<img src="qrcode.png" alt="使用微信扫描支付">';   
}
 
//调用查看结果
echo scerweima('https://www.baidu.com');
 
3.2. 在生成的二维码中加上logo(生成图片文件)    每调用一次都会在本地生成一张二维码图片

image.png

php

复制代码
function scerweima1($url=''){undefined
    require_once 'phpqrcode.php';
    $value = $url;                    //二维码内容  
    $errorCorrectionLevel = 'H';    //容错级别  
    $matrixPointSize = 6;            //生成图片大小  
    //生成二维码图片
    $filename = 'qrcode/'.microtime().'.png';
    QRcode::png($value,$filename , $errorCorrectionLevel, $matrixPointSize, 2);  
    
    $logo = 'qrcode/logo.jpg';     //准备好的logo图片   
    $QR = $filename;            //已经生成的原始二维码图  
 
    if (file_exists($logo)) {   
        $QR = imagecreatefromstring(file_get_contents($QR));           //目标图象连接资源。
        $logo = imagecreatefromstring(file_get_contents($logo));       //源图象连接资源。
        $QR_width = imagesx($QR);            //二维码图片宽度   
        $QR_height = imagesy($QR);            //二维码图片高度   
        $logo_width = imagesx($logo);        //logo图片宽度   
        $logo_height = imagesy($logo);        //logo图片高度   
        $logo_qr_width = $QR_width / 4;       //组合之后logo的宽度(占二维码的1/5)
        $scale = $logo_width/$logo_qr_width;       //logo的宽度缩放比(本身宽度/组合后的宽度)
        $logo_qr_height = $logo_height/$scale;  //组合之后logo的高度
        $from_width = ($QR_width - $logo_qr_width) / 2;   //组合之后logo左上角所在坐标点
        
        //重新组合图片并调整大小
        /*
         *    imagecopyresampled() 将一幅图像(源图象)中的一块正方形区域拷贝到另一个图像中
         */
        imagecopyresampled($QR, $logo, $from_width, $from_width, 0, 0, $logo_qr_width,$logo_qr_height, $logo_width, $logo_height); 
    }   
  
    //输出图片  
    imagepng($QR, 'qrcode.png');  
    imagedestroy($QR);
    imagedestroy($logo);
    return '<img src="qrcode.png" alt="使用微信扫描支付">';   
}
 
//调用查看结果
echo scerweima1('https://www.baidu.com');
 
3.3. 生成二维码(不生成图片文件)   不生成文件,会直接输出二维码到浏览器中。
ini

复制代码
function scerweima2($url=''){undefined
    require_once 'phpqrcode.php';
    
    $value = $url;                    //二维码内容
    $errorCorrectionLevel = 'L';    //容错级别 
    $matrixPointSize = 5;            //生成图片大小  
    //生成二维码图片
    $QR = QRcode::png($value,false,$errorCorrectionLevel, $matrixPointSize, 2);
}
//调用查看结果
scerweima2('https://www.baidu.com');
作者:么得感情的攻城狮
链接:https://juejin.cn/post/7078630229492629517
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

php file_get_contents怎么读取图片 - 问答 - 亿速云

mikel阅读(128)

来源: php file_get_contents怎么读取图片 – 问答 – 亿速云

要使用file_get_contents函数读取图片,需要提供图片的URL地址作为参数。示例代码如下:

$imageUrl = 'https://example.com/image.jpg';
$imageData = file_get_contents($imageUrl);

// 保存图片到本地文件
file_put_contents('path/to/save/image.jpg', $imageData);

在上述示例中,$imageUrl是图片的URL地址,$imageData是通过file_get_contents函数获取的图片内容。然后,可以使用file_put_contents函数将图片内容保存到本地文件中。请将path/to/save/image.jpg替换为您要保存图片的本地路径。

请注意,使用file_get_contents读取大型或者远程服务器上的图片可能会导致内存溢出,这种情况下可以考虑使用stream_context_create函数和fopen函数来处理。以下是一个使用stream_context_createfopen函数的示例:

$imageUrl = 'https://example.com/image.jpg';

$context = stream_context_create(['http' => ['user_agent' => 'Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/35.0']]);
$imageFile = fopen('path/to/save/image.jpg', 'w');
stream_copy_to_stream(fopen($imageUrl, 'r', false, $context), $imageFile);
fclose($imageFile);

在上述示例中,stream_context_create函数用于创建一个包含用户代理信息的上下文,避免某些远程服务器拒绝访问的限制。然后,使用fopen函数打开本地文件和远程图片文件,并使用stream_copy_to_stream函数将远程图片内容复制到本地文件。最后,关闭文件句柄。同样,请将path/to/save/image.jpg替换为您要保存图片的本地路径。

购买使用亿速云服务器,可以极大降低初创企业、中小企业以及个人开发者等用户群体的整体IT使用成本,无需亲自搭建基础设施、简化了运维和管理的日常工作量,使用户能够更专注于自身的业务发展和创新。

php将远程图片保存到本地,php使用file_get_contents 将远程图片保存到本地_php保存图片到本地-CSDN博客

mikel阅读(122)

来源: php将远程图片保存到本地,php使用file_get_contents 将远程图片保存到本地_php保存图片到本地-CSDN博客

需求背景:将远程图片保存至本地

PHP可以使用 file_get_contents 函数和 file_put_contents 函数来将远程图片保存到本地。具体步骤如下:

使用 file_get_contents 函数获取远程图片的内容。

$url = ‘http://example.com/image.jpg’;
$imgContent = file_get_contents($url);

使用 file_put_contents 函数将获取到的图片内容保存到本地文件中。

$localPath = ‘/path/to/local/image.jpg’;
file_put_contents($localPath, $imgContent);

完整的代码如下所示:

$url = ‘http://example.com/image.jpg’;
$localPath = ‘/path/to/local/image.jpg’;
$imgContent = file_get_contents($url);
file_put_contents($localPath, $imgContent);

在上面的代码中,我们先定义了远程图片的 URL 和本地图片的路径,然后使用 file_get_contents 函数获取远程图片的内容,并将其保存到 $imgContent 变量中。最后,使用 file_put_contents 函数将 $imgContent 的内容保存到本地文件中。
需要注意的是,使用该方法保存远程图片时,需要确保 PHP 环境对远程文件的访问权限。如果远程图片需要进行身份验证或者需要通过代理服务器访问,可以使用 CURL 函数来获取图片内容。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/gjwgjw1111/article/details/129572956

使用phpqrcode生成二维码 - 简书

mikel阅读(126)

来源: 使用phpqrcode生成二维码 – 简书

在项目中使用的到了显示二维码,网上搜了一下php主要使用phpqrcode实现。

        $data = 'www.baidu.com'; 
        $level = 'L';// 纠错级别:LMQH
        $size = 6;// 点的大小:110,用于手机端4就可以了
        
        include EXTEND_PATH.'org/phpqrcode/phpqrcode.php';
        $QRcode = new \QRcode();
        ob_start();
        $QRcode->png($data,false,$level,$size);
        $imageString = base64_encode(ob_get_contents());
        ob_end_clean();
        //$path=ROOT_PATH.'public/static/images/qrcode/';
        //$QRcode->png($data,$path.$fileName,$level,$size);// 生成本地图片
        return $imageString;

上面的代码是生成一个base64的字符串,在页面如下使用就可以显示图片了。

<img src="data:image/png;base64,这里是base64编码内容" />

关于QRcode::png方法参数说明:

1.第一个参数$text,就是上面代码里的URL网址参数,
2.第二个参数$outfile默认为否,不生成文件,只将二维码图片返回,否则需要给出存放生成二维码图片的路径
3.第三个参数$level默认为L,这个参数可传递的值分别是L(QR_ECLEVEL_L,7%),M(QR_ECLEVEL_M,15%),Q(QR_ECLEVEL_Q,25%),H(QR_ECLEVEL_H,30%)。这个参数控制二维码容错率,不同的参数表示二维码可被覆盖的区域百分比。利用二维维码的容错率,我们可以将头像放置在生成的二维码图片任何区域。
4.第四个参数$size,控制生成图片的大小,默认为4
5.第五个参数$margin,控制生成二维码的空白区域大小
6.第六个参数$saveandprint,保存二维码图片并显示出来,$outfile必须传递图片路径。

第二个参数默认是false,方法返回的是二进制的图片流。生成在缓冲区的,在页面输出的时候会从缓冲区送到浏览器。所以在代码中是使用log输出是不会记录在日志中的,也不需要使用echo进行内容输出。所以直接使用base64_encode(QRcode::png)是没有用的。
这里使用到了ob_start()方法,打开输出缓冲区,所有的输出信息不在直接发送到浏览器,而是保存在输出缓冲区里面。这里就是把生成的图片流从缓冲区保存到内存对象上,使用base64_encode变成编码字符串,通过json返回给页面。
看一下直接使用QRcode::png返回图片流到浏览器


最后简单说一下ob:
ob是output buffering的简称,而不是output cache,ob用对了是能对速度有一定的帮助,但是盲目的加上ob函数,只会增加CPU额外的负担。说说ob的基本作用:
1.防止在浏览器有输出之后再使用setcookie,或者header,session_start函数造成的错误。(我本以为最开始说的代码是这样的作用,但后来朋友说不是的),其实这样的用法少用为好,养成良好的代码习惯。
2.捕捉对一些不可获取的函数的输出,比如phpinfo会输出一大堆的HTML,但是我们无法用一个变量例如$info=phpinfo();来捕捉,这时候ob就管用了。
3.对输出的内容进行处理,例如进行gzip压缩,例如进行简繁转换,例如进行一些字符串替换。
4.生成静态文件,其实就是捕捉整页的输出,然后存成文件,经常在生成HTML,或者整页缓存中使用。
对于刚才说的第三点中的GZIP压缩,可能是很多人想用,却没有真真用上的,加一个ob_gzhandler这个回调函数就可以了。

ob_start(ob_gzhandler);
内容
echo ob_get_contents() ;
ob_end_flush();

作者:可乐爱上咖啡
链接:https://www.jianshu.com/p/768e72938237
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

宝塔面板建站后如何本地调试 - 问答 - 亿速云

mikel阅读(129)

来源: 宝塔面板建站后如何本地调试 – 问答 – 亿速云

使用宝塔建站后需要在本地实现调试,要在本机hosts文件中进行配置

1.在本机上使用记事本打开hosts文件,hosts文件路径:C:\Windows\System32\Drivers\etc;

2.hosts文件打开后,在文件最后面添加宝塔建站的网站域名,如127.0.0.1 www.123.com,保存即可;

 

购买使用亿速云服务器,可以极大降低初创企业、中小企业以及个人开发者等用户群体的整体IT使用成本,无需亲自搭建基础设施、简化了运维和管理的日常工作量,使用户能够更专注于自身的业务发展和创新。

linux宝塔面板安装composer的方法[全网详解]_宝塔 composer-CSDN博客

mikel阅读(123)

来源: linux宝塔面板安装composer的方法[全网详解]_宝塔 composer-CSDN博客

概念:
Composer是一个PHP依赖管理器,可以方便地管理和安装PHP项目所依赖的库和软件包。它可以自动下载、安装和更新这些库,同时确保它们与项目的其他部分兼容。Composer可以通过一个名为composer.json的配置文件来配置,该文件列出了项目所依赖的库、版本等信息。Composer还可以从Packagist等仓库中查找和下载各种PHP库和软件包。由于Composer的出现,开发人员不再需要手动下载、安装和配置PHP库,从而大大简化了PHP项目的开发和维护过程。

有些项目安装会用到composer,如果直接安装会报错“Warning: putenv() has been disabled”。

 

所以宝塔面板安装composer我们需要删除禁用函数,删除之后,才可以正常安装。下面就说说,宝塔面板linux版本如何安装composer!

1、删除禁用函数

宝塔面板默认禁用一些安装 Composer 要用到的 3 个函数如下:

putenv() 、 pcntl_signal() 、 proc_open(),

“PHP管理”→“禁用函数”→“删除putenv”。

 

这样删除就可以了。其他诸如此类,这里不再赘述。

2、全局安装

1)安装之前更新服务器软件包

如果是centos系统,可以使用 SSH 执行下方命令:

yum update -y
如果是debian类的

apt update
删除禁用函数和更新软件包后,就可以愉快安装composer了。这里用全局安装,安装命令如下:

cd ~
php -r “copy(‘https://install.phpcomposer.com/installer’, ‘composer-setup.php’);” # 将安装脚本下载到当前目录
php composer-setup.php # 运行安装脚本
php -r “unlink(‘composer-setup.php’);” # 删除安装脚本
mv composer.phar /usr/local/bin/composer # 全局安装 composer(配置系统环境变量)

如果是国内服务器,可以会下载缓慢,可以换源解决。将 composer 源改成阿里云的镜像

composer config repo.packagist composer https://mirrors.aliyun.com/composer/

安装完成后,可以用命令:“composer –version”来查看你安装的版本号。

 

3、局部安装

这里简单提一下,上述下载Composer的过程正确执行完毕后(最后一步不要执行),可以将composer.phar文件复制到任意目录(比如项目根目录下),然后通过php composer.phar指令即可使用Composer了

不过还是推荐用全局安装~~~

4、更换镜像源

随着Composer的发展,已经很多大厂商都加入了Composer的镜像源,强烈推荐使用阿里云的,同步频率快,速度也很稳定,不过你可能对其他的也有兴趣:

阿里云Composer镜像
https://mirrors.aliyun.com/composer/
腾讯云Composer镜像
PHP Composer
华为云Composer镜像
https://repo.huaweicloud.com/repository/php/
安畅云Composer镜像
https://php.cnpkg.org
5、最后

宝塔安装composer会报错的处理方法,大概就是这样了 。如果是lnmp环境那么需要编辑PHP配置文件:

vi /usr/local/php/etc/php.ini进入编辑状态。

输入/,进入搜索模式,找到disable_functions

寻找disable_functions字符串,将后面的putenv删除。
————————————————
版权声明:本文为CSDN博主「奔跑的蜗牛.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/MrWangisgoodboy/article/details/129929934

.net 温故知新:【10】.NET ORM框架EFCore使用入门之CodeFirs、DBFirst - XSpringSun - 博客园

mikel阅读(104)

来源: .net 温故知新:【10】.NET ORM框架EFCore使用入门之CodeFirs、DBFirst – XSpringSun – 博客园

前言:本系列是我自己学习.net相关知识,以便跟上.net跨平台的步伐,目前工作原因基本在.net Framework4.7以下,所以才有了这一系列的学习总结,但是并不是从基本的C#语法和基础知识开始的,而是围绕.net core以后平台的重要设计和差异进行温故知新。目的在于通过要点的梳理最后串联起整个跨平台框架。之前的几篇算是把框架重要设计和框架重要知识点复习了,当然什么系统都可能使用到ORM框架。所以这里为了整个过程的完整连续性加入一个EFCore的示例,ORM不算详细写了,毕竟ORM框架可以根据需求选择很多,如果再详细那又是另外一个系列了,这里只做简单介绍。从这篇ORM完成之后就将进入ASP.NET core的学习总结!

EFCore

Entity Framework Core (EF Core) 是适用于 .NET 的新式对象数据库映射器。 它支持 LINQ 查询、更改跟踪、更新和架构迁移。

EF Core 通过数据库提供程序插件模型与 SQL Server/Azure SQL 数据库、SQLite、Azure Cosmos DB、MySQL、PostgreSQL 和更多数据库配合使用。

EFCore入门

在上面的EFCore介绍中我们又看到了提供程序描述,之前文章多次提到这个提供程序是.net框架中随处可见的,也就是通过这些不同的提供程序实现扩展和适配。本文我用两种数据库,sqlite和SQLServer并分别用code-first(代码优先)模式和db-frist(数据库优先)模式演示EFCore的使用。

1、Code First

新建一个.net 6.0 控制台应用程序,安装nuget包(EFCore的sqlite提供程序):

Install-Package Microsoft.EntityFrameworkCore.Sqlite

重要依赖Package Microsoft.EntityFrameworkCore包会自动安装。

编写SqliteContext类构成模型的上下文类,实体类:Student、Course。

namespace EFCoreDemo.Sqlite
{
    public class SqliteContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }

        /// <summary>
        /// sqlite 数据库文件路径
        /// </summary>
        public string DbPath { get; }

        public SqliteContext()
        {
            var folder = Environment.CurrentDirectory;
            DbPath = System.IO.Path.Join(folder, "CodeFirst.db");
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
            => options.UseSqlite($"Data Source={DbPath}");
    }

    /// <summary>
    /// 学生
    /// </summary>
    public class Student
    {
        public int id { get; set; }
        public string name { get; set; }

        public List<Course> courses { get; set; }
    }

    /// <summary>
    /// 课程
    /// </summary>
    public class Course
    {
        public int id { get; set; }

        public string name { get; set; }
    }
}

接着我们安装包Microsoft.EntityFrameworkCore.Tools用来生成数据库

Install-Package Microsoft.EntityFrameworkCore.Tools

然后在“包管理器控制台(PMC)”中使用命令:

Add-Migration InitialCreate

提示创建成功:

PM> Add-Migration InitialCreate
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> Update-Database
Build started...
Build succeeded.
Applying migration '20221130040124_InitialCreate'.
Done.

搭建基架,为模型创建一组初始表。该命令完成后会生成一个Migration文件夹包含两个类,一个数据库创建类InitialCreate是我们定义的,可以按需求更改名称。一个模型快照类SqliteContextModelSnapshot上面的[DbContext(typeof(SqliteContext))]属性标识类所属的DbContext。使用该atrribute确定迁移应用于哪个上下文。

由于这是项目的第一次迁移,如果我们修改了模型后再Add-Migration生成的时候EFCore 会在添加列之前将更新的模型与旧模型的快照进行比较。基于该比较,EF Core 检测变化,并添加适当的迁移而不是再重新生成数据库。

image

最后运行命令Update-Database生成数据库和表,数据库在我们配置的程序路径下。

PM> Update-Database
Build started...
Build succeeded.
Applying migration '20221130040124_InitialCreate'.
Done.

image

生成的sqlite数据库如图,因为我们定义了Student、Course实体,所以会生成两个表以及表的字段,同时还会生成一个历史表,用于记录我们每次迁移的记录。另外在Student类里面我们定义了一个public List<Course> courses { get; set; } 属性,表示学生拥有哪些课程,这样相当于是一个外键关系,EFCore会为我们在Coures表里面创建一个Sudentid的外键来表达关联关系。同时我们查询学生的话理论上也能查出学生拥有的课程,接下来我们向数据库中插入数据并进行查询。

注意在命令生成的时候CurrentDirectory是项目目录,我们运行的时候要把生成的CodeFirst.db复制到bin/Debug

        static void Main(string[] args)
        {
            //实例化context
            SqliteContext context = new SqliteContext();
            //添加数据
            for (int i = 0; i < 5; i++)
            {

                List<Course> courses = new()
                {
                    new Course()
                    {
                        name = "语文"+i
                    },
                     new Course()
                    {
                        name = "数学"+i
                    },
                };

                context.Students.Add(new Student()
                {
                    name = "学生" + i,
                    courses = courses
                });
                context.SaveChanges();
            }
            //查询
            var students = context.Students.Include(t=>t.courses).ToList();
            students.ForEach(e =>
            {
                Console.Write(e.name);
                e.courses.ForEach(e => { Console.Write(e.name); });
                Console.WriteLine();
            });

            var student = context.Students.SingleOrDefault(t => t.name=="学生3");
            Console.WriteLine($"id:{student.id},name:{student.name}");
            Console.ReadKey();
        }

image

查询如果要包含外键关联的数据,需要用Include方法。不然上面的结果第一次可以用,第二次就查询不出来,因为第一次的数据添加后会直接在上下文Context里面。

2、 DB Frist

首先我们建一个SQLServer数据库,然后反向建两张一样的表。

image

在项目中安装 Microsoft.EntityFrameworkCore.Design 的 nuget 包。
Install-Package Microsoft.EntityFrameworkCore.Design
由于上面我安装Microsoft.EntityFrameworkCore.Tools nuget包的时候依赖项已经安装了所以就不需要再安装了。

然后安装SQLServer的提供程序 nuget 包。

Install-Package Microsoft.EntityFrameworkCore.SqlServer

image

安装好 nuget 包后在程序包管理器控制台里面使用命令:

Scaffold-DbContext 'Data Source=192.168.40.165;Initial Catalog=DBFirst;User Id=sa;Password=123456;Encrypt=False' -Context SqlServerContext    -OutputDir DBFirst Microsoft.EntityFrameworkCore.SqlServer
  • -Context:指定DbContext 类名称,如果不指定则是数据库名称+Context。
  • -OutputDir:指定生成的模型目录。

除此之外该命令还有其它参数包括:

  • -ContextDir:指定DbContext类生成目录。
  • -ContextNamespace:覆盖 DbContext 类的命名空间。
  • -Namespace: 覆盖所有输出类的命名空间。

生成的DBContext和模型:

image

使用SqlServerContext 查询数据:

            var students = context.Students.Include(t=>t.Courses).ToList();
            students.ForEach(e =>
            {
                Console.Write(e.Name);
                e.Courses.ToList().ForEach(e => { Console.Write("   "+e.Name); });
                Console.WriteLine();
            });

            var student = context.Students.SingleOrDefault(t => t.Name=="李四");
            Console.WriteLine($"id:{student.Id},name:{student.Name}");

image

EFCore的其它重要知识点

本篇作为入门使用,其它EFCode的重要知识点还是建议使用时候查看官方文档即可。
我认为EFCore的重要知识点包括但不限于:

  • EFCore中的约定大于配置,比如模型如果有Id字段默认就是主键。
  • 一对多关系配置和获取,上面示例中学生有哪些课程就是一对多,查询关联要用includ。
  • 多个外键字段的配置。
  • 一对多,多对多关系。
  • Iqueryable的作用和数据延迟加载,在我们查询数据的时候列表数据以Iqueryable类型返回,如果我们不是调用获取结果api,则不会立即查询数据库,而是等到使用tolist()、count()、max()等方法时才会查询数据返回结果。这样有利于我们在代码中复用Iqueryable,比如不同的if条件拼接后组成不同的查询语句。
  • EFcore 缓存。
  • AsNoTracking使用,EFCore默认会跟踪实体,也就是保存在内存中,用于更新删除等操作。如果只是查询数据而不用跟踪则使用AsNoTracking查询。
  • 并发控制。
    …..